GUI koppelen aan datalogica voor wederzijdse communicatie

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • m1dnigh7
  • Registratie: Januari 2006
  • Laatst online: 26-09 15:19
Hallo beste mensen,

Ik moet voor school een chatclient ontwerpen en voor een ander vak een website. Nu alles gaat wel vlotjes maar bij beide zit ik met een conceptueel probleem. Ik zal het abstract proberen uit te leggen aan de hand van m'n chatclient. Ik denk namelijk dat ik een belangrijk concept niet ken van programmeren ofzoiets..

Here goes..

Ik heb dus een javaproject "Chat_Client". Hierin zitten 2 packages "gui" en "connection". In de "gui" package zit een JFrame (de gui dus). In de package "connection" zit een klasse die ik zou willen instantieren in mijn gui, om zo verbinding te leggen met de server.

Nu, een berichtje sturen zou als volgt moeten gaan:
gui.ChatClientGui.java krijgt invoer in een tekstvak. Ik klik op de knop om dit te verzenden en roep zo de actionperformed methode aan van die knop. Daarachter instantieer ik connetion.ChatClient.java. In connectin.ChatClient roep ik SendMessage(String msg) aan en deze verstuurt die naar de server. De server krijgt dit berichtje binnen via een inputstream en zal deze dan controleren en zal een antwoord verzenden naar de inputstream van connection.ChatClient. Nu komt dit toe in een thread die buiten de klasse loopt, en kan ik dus het antwoord van de server niet teruggeven in de return van mijn methode "SendMessage()" van de klasse connection.ChatClient.java. Hoe kan ik vanuit die thread dan een texbtox bijvoorbeeld updaten in mijn GUI?

Ik hoop dat het een beetje duidelijk is...

Alvast bedankt!

Acties:
  • 0 Henk 'm!

  • hiekikowan
  • Registratie: Februari 2011
  • Laatst online: 07-10 22:53
Ik weet niet of ik je helemaal goed begrepen heb, maar je (2na) laatste regel doet me vermoeden dat je de inhoud op het scherm wilt vernieuwen zonder de pagina geheel opnieuw te laden. Zoiets kan bereikt worden met AJAX...

Acties:
  • 0 Henk 'm!

  • m1dnigh7
  • Registratie: Januari 2006
  • Laatst online: 26-09 15:19
Neen, je snapt het niet goed, mijn fout. Ik ga hier even mijn projectje opschonen en dan plaats ik het hier zodat jullie er wat meer kunnen van maken van die uitleg. Sorry in elk geval en alvast bedankt!

Acties:
  • 0 Henk 'm!

  • Mad Marty
  • Registratie: Juni 2003
  • Laatst online: 01:07

Mad Marty

Je bent slimmer als je denkt!

Het lijkt me de bedoeling van je huiswerk dat je zélf een oplossing bedenkt. Maar goed, waar zat je zelf aan te denken om dit op te lossen? Je hoeft niet per se direct in Java-termen te denken, maar probeer het eerst eens concreet in gewone taal te formuleren wat je programma op dat moment moet doen.

Rail Away!


Acties:
  • 0 Henk 'm!

  • Remus
  • Registratie: Juli 2000
  • Laatst online: 15-08-2021
Kijk eens naar SwingUtilites.invokeLater(), daar mee kan je vanaf een andere Thread de acties uitvoeren op de GUI EventThread. Voor meer geavanceerde oplossingen kan je kijken naar SwingWorker.

Acties:
  • 0 Henk 'm!

  • Kwistnix
  • Registratie: Juni 2001
  • Laatst online: 22:34
Je zou eens kunnen kijken naar de Socket Communication tutorial op de Oracle website.
Daar zijn de client en server echter wel via Sockets ontkoppeld - iets wat ik niet echt uit jouw verhaal kan halen.

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Mad Marty schreef op vrijdag 02 december 2011 @ 16:26:
Het lijkt me de bedoeling van je huiswerk dat je zélf een oplossing bedenkt
Huiswerktopics zijn niet per definitie fout!

@m1dnigh7: Zou je even een voorstel voor een fatsoenlijke topictitel die de lading wél dekt willen doen middels de Afbeeldingslocatie: http://tweakimg.net/g/forum/images/icons/icon_hand.gif-knop? Thanks

Verder stellen we 't ook op prijs als je onze Quickstart hanteert bij 't openen van een topic; ik wacht even je aangekondigde post af, maar 't zou fijn zijn als daarmee je topic dan meteen voldoet aan die quickstart. Scheelt ijzerwerk op je topic Afbeeldingslocatie: http://tweakers.net/ext/f/HJzEooTof8o04dDbnFezgFuY/full.gif ;) Zorg dat je je in ieder geval beperkt tot relevante code (en bijbehorend gebruik van code tags) mocht je die willen plaatsen.

[ Voor 70% gewijzigd door RobIII op 02-12-2011 17:10 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • dingstje
  • Registratie: Augustus 2002
  • Laatst online: 02-01-2024
Het lijkt me dat de TS eerder nood heeft aan een artikel/boek over software architecture, dan specifieke mogelijkheden als invokeLater of sockets. Die zijn allemaal ongetwijfeld heel nuttig voor het probleem, maar de vraag komt eigenlijk meer neer op de klassieke 'hoe structureer ik mijn applicatie' en 'hoe koppel ik de verschillende componenten aan elkaar, zonder een interdependent zooitje van te maken' (aangezien de gui en connection 'componenten' blijkbaar al klaar zijn). Klassieke zoekterm is dan natuurlijk MVC, als de meest gebruikte structuur (of minstens een poging tot gebruik).

If you can't beat them, try harder


Acties:
  • 0 Henk 'm!

  • m1dnigh7
  • Registratie: Januari 2006
  • Laatst online: 26-09 15:19
Oke here goes!

Ik heb tot nu aan die applicatie wat zitten werken zodat ik het probleem duidelijker kan formuleren.

Wat wil ik maken?
Een applicatie in Java om te chatten. Het betreft een serverapplicatie met bijhorende clientapplicatie. De server heeft geen gui. Dan de clientapplicatie die werkt wel met een gui.

Wat heb ik al?

Ik heb al een 'werkende' applicatie die berichten naar de server kan sturen, en de server logged deze dan in de commandline.
Ik start mijn servertje op en vervolgens m'n client. Ik kan op een "connect" knop klikken die dan verbinding maakt. Zoals hieronder:
De code achter de button:

Java:
1
2
3
4
cc.ConnectToServer();
//cc is een private attribuut van de GUI klasse. Het is een object van de klasse "ChatClient" die al
//het verkeer regelt tussen de server en deze klasse zelf. Het object zelf instantieer ik in mijn constructor
//van de gui klasse


ConnectToServer()
Java:
1
2
3
4
server = new Socket(host, port); //proberen connecten met de server via een socket
System.out.println("Connected to server at " + host +":" + port);
out = new PrintWriter(server.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(server.getInputStream()));


Wat dit al doet is gewoon de verbinding leggen tussen de draaiende server. Nu kan ik beginnen met berichten te sturen naar de server en dit doe ik als volgt:

Als ik een bericht ingetypt heb in het textvak en op send klik roept hij deze code aan:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
String message = txtMessage.getText();
txtMessage.setText("");
String reply = null;
try {
      reply = cc.SendMessage(message);
      } 
catch (IOException ex) 
      {
            System.err.println(ex);
       }
txtMessagebox.append("\n" + reply); //de server antwoordt elke keer "Server: message received!"
}


Die code roept dan de methode SendMessage(String p) aan, en die is niet meer dan dit:
Java:
1
2
3
4
5
public String SendMessage(String msg) throws IOException
{
    out.println(msg);
    return in.readLine();
}


Nu bij de server komen er threads aan te pas. Dit is zodat ik meerdere clients kan gebruiken, want niemand wil immers tegen een server praten.

De server instantieert per verbonden socket een thread die via een while() blijft controleren op inkomende berichten.
Ik ga hier even de volledige Runnable klasse zetten zodat het duidelijk is:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class ClientHandler implements Runnable {
    private Socket client;
    private ChatServerProtocol protocol = null;
    private BufferedReader in = null;
    private PrintWriter out = null;
    
    ClientHandler(Socket client)
    {
        this.client = client;
    }

    @Override
    public void run() {
        try
        {
            //een inputstream van de client naar de server
            in = new BufferedReader(new InputStreamReader(client.getInputStream()));
            //een outputstream verkrijgen naar diezlefde client
            out = new PrintWriter(client.getOutputStream(), true);
        }
        catch(IOException e)
        {
            System.err.println(e);
            return;
        }
        //hier gaan we dan loopen om berichten van de client te ontvangen!
        String msg, serverResponse;
        protocol = new ChatServerProtocol(this);
        try 
        {
            while((msg = in.readLine()) != null)
            {
                //hier komt elk bericht toe dat naar de server
                //gestuurd wordt. Het zal eerst door het protocol 
                //geprocessed worden.
                serverResponse = protocol.ProcessMessage(msg);
                System.out.println("Client says: "+ msg);
                out.println("Server: message received!");
            }
        } 
        catch (IOException e) 
        {
            System.err.println(e);
        }
    }//run
        public void sendMsg(String msg) {
        out.println(msg);
    }
   
}


De server krijgt het bericht en verwerkt het. Dan zet hij elke keer het "Server: message received" bericht op de PrintWriter en dit komt dan aan bij de client en hier wringt het schoentje.

Ik stuur het bericht van client A naar de server in de methode SendMessage(), en in die methode ontvang ik meteen het antwoord van de server.

Het probleem
Hoe ontvangt mijn client berichten van andere clients, en hoe krijg ik deze dan tot in de GUI klasse?

Wat denk ik?

Ik denk dat ik in client applicatie een thread (?) moet aanmaken die luistert naar de server in een while() zoals de server dat doet. Dit lijkt mij logisch. Maar hoe kan ik dan de GUI klasse zelf doen luisteren naar de "ChatClient" klasse, zodat de gui weet "oh, daar komt een berichtje binnen van de server". Nu werkt het geheel eigelijk maar in 1 weg. De client kan sturen, maar hij is totaal onbewust van de berichten die de server stuurt naar de client? Ik kan nu een antwoord ontvangen omdat mijn methode SendMessage() niet stopt zolang hij een antwoord krijgt. Ik hoop dat het duidelijk is, en nee ik ben er echt nog niet uit :(

Acties:
  • 0 Henk 'm!

Verwijderd

m1dnigh7 schreef op vrijdag 02 december 2011 @ 19:42:
Ik denk dat ik in client applicatie een thread (?) moet aanmaken die luistert naar de server in een while() zoals de server dat doet. Dit lijkt mij logisch. Maar hoe kan ik dan de GUI klasse zelf doen luisteren naar de "ChatClient" klasse, zodat de gui weet "oh, daar komt een berichtje binnen van de server". Nu werkt het geheel eigelijk maar in 1 weg. De client kan sturen, maar hij is totaal onbewust van de berichten die de server stuurt naar de client? Ik kan nu een antwoord ontvangen omdat mijn methode SendMessage() niet stopt zolang hij een antwoord krijgt. Ik hoop dat het duidelijk is, en nee ik ben er echt nog niet uit :(
Je clients zullen inderdaad een thread moeten hebben die "Listened" op de connectie met de server voor nieuwe berichten. Deze thread maak je zo dat er zich listeners op kunnen registeren die events afvuurd (op de EDT). Zoiets als dit (uit me hoofd, zal ongetwijfeld niet comilen en ben wellicht nog iets vergeten :) ):

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class ChatClient implements Runnable {
 @Override
 public void run() {
   // Alle socket stuff voor het ontvangen van berichten...
   
   messageReceived(msg);
 }

 private void messageReceived(final String msg) {
  synchronized(listeners) {
   for (final ChatEventListener listener : listeners) {
    // Dit zorgt ervoor dat de UI zijn events afhandeld op de EDT. Erg belangrijk bij Swing!!! 
    // Nooit componenten updaten vanaf een niet-EDT thread.
    SwingUtilities.invokeLater(new Runnable() {
     @Override
     public void run() {
       listener.newChatMessage(msg);
     }
   }
  }
 }

 private final List<ChatEventListener> listeners = new ArrayList<ChatEventListener>();

 public void addChatEventListener(final ChatEventListener listener) {
  synchronized(listeners) {
   listeners.add(listener);
  }
 }

 public void removeChatEventListener() {
  synchronized(listeners) {
   listeners.remove(listener);
  }
 }
}


Java:
1
2
3
public interface ChatEventListener {
 public void newChatMessage(String msg);
}


Je GUI laat je dan zich registeren als listener en die events verwerken:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ChatPanel extends JPanel implements ChatEventListener  {

  private final JTextArea chatTextArea = new JTextArea();
  private final JScrollPane chatScrollPane = new JScrollPane(chatTextArea);

  public ChatPanel(ChatClient client) {
   add(chatScrollPane);
   // Bad practice eigenlijk, de 'this' reference laten 'onstsnappen' van een instantie
   // die nog niet volledig geconstruct is...
   client.addChatEventListener(this);
  }

  @Override
  public void newChatMessage(String msg) {
    chatTextArea.append(msg+"\n" ); 
  }

}

Acties:
  • 0 Henk 'm!

  • m1dnigh7
  • Registratie: Januari 2006
  • Laatst online: 26-09 15:19
Dit is net wat ik nodig had! Jullie zijn hartelijk bedankt! :) Ik had natuurlijk wel geen uitgewerkt voorbeeld verwacht maar dat maakt het mij natuurlijk makkelijker! Ik snap niet dat ik zo iets (simpel?) nog steeds niet moeten gebruiken heb.. Soms voel ik me zo dom!

Bedankt mensen! Ik laat straks nog weten hoe het gelopen is, hopelijk is de applicatie klaar vandaag!

Edit:

Ik heb even moeten prutsen maar voorlopig werkt het weer! Toegegeven dat ik enkele stukken code nog niet goed snap maar het concept dat snap ik wel klaar en duidelijk! :) Nogmaals bedankt beste mensen! Ik heb wel naar mijn lector een mailtje gestuurd of hij in de les eens niet een simpl voorbeeldje zou willen maken. Zo heb ik het zelf bouwen van dit concept onder de knie.

[ Voor 34% gewijzigd door m1dnigh7 op 03-12-2011 16:57 ]


Acties:
  • 0 Henk 'm!

  • m1dnigh7
  • Registratie: Januari 2006
  • Laatst online: 26-09 15:19
Hallo beste mensen, hier ben ik alweer! :)

Mijn chatclient werkt prachtig, ik heb er nog enkele uren op verder gewerkt en nu kan ik al chatten, krijg ik een lijst met contactpersonen etc. Ik ben blij dat ik al zo een heel eind geraakt ben en dat het prachtig en solide werkt. (voor zover ik het al getest heb natuurlijk.) En daarvoor bedank ik jullie nogmaals!

Nu zit ik met een ander probleem. Ik ben bezig met er file transfer in te bouwen. Hoe werkt dit?

ik: zender
hij: ontvanger

De client zendt naar de server "ik said: SENDFILE <filesize> <host> <port>"
Vervolgens zal de client een serversocket aanmaken om te luisteren naar verbindingen van de client (die moet dus nog komen)

De ontvanger krijgt dit toe via de server en weet dat hij een socket moet openen om een file te ontvangen.
De ontvanger zal een instantie aanmaken van een filesender en deze zal verbinden met de serversocket op de juiste poort en host.

Tot hier toe werkt het.

Nu wil ik een file verzenden en dat "lukt" wel. Wat lukt er dan net? Wel, de ontvanger krijgt inderdaad alle informatie door en maakt de file aan (abc.txt) maar deze bevat geen tekst. Dus er is iets met de filestream fout.

Als ik wat google lijkt het mij dat iedereen dezlefde tutorial heeft gebruik net zoals ik dat gedaan heb lol :)

Nu zou ik een beetje lui willen zijn en vragen of jullie het zo kunnen zien wat er fout is? Ik ga ondertussen zelf ook nog wat verder zoeken natuurlijk! :)

*snip* dan ben ik even een beetje lui en laat ik 't alleen bij deze mbr en mag je zelf uitzoeken waarom ik dat gedaan heb ;)

Alvast bedankt mensen!


Edit: Het is me zelf gelukt! Ik post hier straks de code voor als er mensen zijn die hier nog problemen mee zouden hebben ! :)

[ Voor 9% gewijzigd door RobIII op 15-01-2012 21:33 ]


Acties:
  • 0 Henk 'm!

  • m1dnigh7
  • Registratie: Januari 2006
  • Laatst online: 26-09 15:19
Roblll, ik snap je bedoeling niet helemaal? En wat is "mbr" dan?

Het programma was zo klaar als het ging raken die dag. Ik ben vrij blij dat het werkt over lan en internet. Er is wel nog wat werk aan, maar dat doe ik deze zomer dan wel als bezigheidstherapie! Het was een schooltaak om te tonen dat we het gebruik van sockets onder de knie hadden. Misschien was dit wel wat overkill, maargoed. Voor de geinteresseerden heb ik het hier even online gezet.

Het probleem met de filetransfer was dat ik het aantal ontvangen bytes niet goed bijhield, en er in de while een -1 stond waardoor ik een infinite loop kreeg bij het ontvangen. Het was dus eigenlijk een simpel probleempje.
Pagina: 1