2017-12-21 13 views
1

Mein Titel ist wahrscheinlich nicht der beschreibendste, aber ich werde versuchen, so viel Code wie möglich zu zeigen in der Hoffnung, dass es jedem helfen wird, meine Frage besser zu verstehen. So fragt meine Clientseite meines Projekts den Server nach Informationen ab. Dies ist ein Beispiel für eine typische Anfrage:Wie auf eine Socket-Eingabe zu hören, ohne andere Anfragen zu blockieren

private String GENERATEGROUPKEY() 
{ 
    /* `out` is a PrintWriter using the sockets output stream */ 
    out.println("GENERATEGROUPKEY"); 

    try 
    { 
     /* `in` is a BufferedReader using the sockets input stream */ 
     String response = in.readLine(); 
     String[] temp = response.split(" "); 

     return temp[1]; 
    } 
    catch (IOException ex) 
    { 
     return null; // throw connection error to client 
    } 
} 

Mein Problem ist, zu jeder Zeit, dass der Server eine unaufgeforderte Nachricht an den Client durch diese gleiche Buchse mit Informationen (darüber nachdenken, es wie ein Chat-Client empfängt eine schicke Botschaft). Meine erfolglose Idee war, einen Thread zu erstellen, der auf eine solche Nachricht wartet, solange wir nicht in der Mitte einer anderen Abfrage sind, aber das war auch nicht erfolgreich, denn obwohl ich diesen Thread unterbreche, ist er immer noch mit den Nachrichten beschäftigt bin zur Kundenanfrage gegangen.

private String GENERATEGROUPKEY() 
{ 
    out.println("GENERATEGROUPKEY"); 
    listenThread.interrupt(); // block listenThread from recieving response 

    try 
    { 
     String response = in.readLine(); 
     String[] temp = response.split(" "); 

     listenThread = new PulseThread(in); // we're done, so allow 
     listenThread.start(); 
     return temp[1]; 
    } 
    catch (IOException ex) 
    { 
     listenThread = new PulseThread(in); // we're done, so allow 
     listenThread.start(); 
     return null; // throw connection error to client 
    } 
} 

Hier ist genau das, was listenThread ist

public class PulseThread extends Thread 
{ 
    private BufferedReader in; 

    public PulseThread(BufferedReader in) 
    { 
     this.in = in; 
    } 

    @Override 
    public void run() 
    { 
     while (true) 
     { 
      if (Thread.currentThread().isInterrupted()) 
      { 
       break; 
      } 
      try 
      { 
       String line = in.readLine(); 
       System.out.println(line); 
       String[] params = line.split(" "); 
       if (params[0].equals("PULSED")) 
       { 
        NotificationManager.sendNotification("You have been pulsed!", "Pulsed by: " + params[1]); 
       } 
      } 
      catch (Exception ex) 
      { 

      } 
     } 
    } 
} 

Ich war vorher unter dem Eindruck, dass in der Mitte des BufferedReader den Faden zu unterbrechen 'mit readLine() s blockierenden Anruf würde nur den blockierenden Anruf abbrechen, es sei denn ich m etwas anderes falsch machen.

Jede Hilfe würde sehr geschätzt werden, danke.

EDIT: So in meine Annahme nur ein paar Zeilen über diesem Satz suchen, scheint es die Unterbrechung der Thread bricht nicht readLine(). Ich denke, die Idee des unterbrechenden Threads ist ein No-Go. Was ist der richtige Weg, dies zu tun?

+0

Mit, err, [tag: multithreading]? Und wo heißt es, dass das Unterbrechen eines Threads die E/A-Operation abbricht, in der es blockiert ist? – EJP

+0

@EJP Ist das keine Multithreading-Frage?Nicht sicher, ob die -1 auf einer legitimen und eindeutigen Frage angemessen war, aber ich schweife ab. Javadocs sagen, und ich zitiere: "Wenn dieser Thread in einer I/O-Operation auf einem unterbrechbaren Kanal blockiert wird, wird der Kanal geschlossen." Gilt das nicht für mich? Wenn nicht, was sind meine möglichen Lösungen, weil ich nicht weiß, was ich tun muss. – Headline

+0

@Headline Das eigentliche Zitat sagt [InterruptibleChannel] (https://docs.oracle.com/javase/8/docs/api/java/nio/channels/InterrupibleChannel.html) wie in einer Java-Klasse. BufferedReader * könnte * eine Ausnahme auslösen, aber da du nichts damit machst, würdest du es nicht wissen. – matt

Antwort

2

Das allgemeine Muster hier ist, dass Sie wollen, dass ein Thread die Ausgabe vom Socket verarbeitet (blockiert während des Wartens) und dann Nachrichten an die richtigen Dinge versendet, die sie angefordert haben.

Eine Implementierung, die ich mag und in mehreren Projekten erfolgreich verwendet habe, ist, eine zufällig generierte ID zu "Anfragen" als Teil eines generischen Headers hinzuzufügen (einschließlich eines Nachrichtentyps) und den Server immer wieder spiegeln zu lassen die Antwort, die es dem Client ermöglicht, eine Anfrage mit einer Antwort zu verknüpfen, ohne sich darum zu kümmern, um welche Art von Nachricht es sich handelt.

Konkret so etwas wie eine SocketMessenger Klasse mit 2 öffentlichen Funktionen: sendRequest(type, body, callback) und registerUnsolicitedHandler(type, callback).

sendRequest erstellt die Nachrichtenkopfzeile mit type und eine zufällig generierte ID, fügt sie neben einem Verweis auf die Rückruffunktion zu einer Liste ausstehender Antworten hinzu und sendet dann die ausgefüllte Nachricht an den Server.

registerUnsolicitedHandler funktioniert wie es der Name andeutet und fügt die Callback-Funktion zu einer Karte von Nachrichtentypen hinzu, die verwendet werden sollen, wenn eine eingehende Nachricht keine ID hat.

In dem separaten Thread, der eingehende Nachrichten verarbeitet, deserialisiert er eingehende Daten, um den Typ und die ID aus dem Header abzurufen. Wenn die Nachricht eine ID hat, durchsucht sie die Liste der ausstehenden Antworten und ruft den entsprechenden Rückruf mit dem Nachrichtentext auf Im Hauptthread beschönige ich einige Details wie Sperren), ansonsten durchsucht es die Liste der nicht angeforderten Handler nach dem angegebenen Typ und ruft diesen Callback auf.

Verwandte Themen