xSockets -> IHandler

Kr0e

Gesperrter Benutzer
Hallo,
ich arbeite mich zur Zeit in das xSockets Framework ein und bin erstmal ziemlich begeistert. Allerdings ist xSockets etwas mager
"tutorialisiert". Hat jemand Erfahrung mit xSockets ? Ich würde ganz gerne wissen, wie genau das Handlersystem funktioniert.

Ich benutze zur Zeit die Multiplexed Lib von xSockets. Beim öffnen eines Servers übergebe ich dann einen MultiplexedProtocolAdapter(IHandler ..)... Problem ist, das ich nun auch will, dass der IHandler den übergebe auch akzeptiert wird... Ich werde aus irgendeinem Grund dann nicht mehr auf onConnect(INonBlockingConnection), onDisconnect(INonBlockingConnection) hingewiesen. Nur noch auf die IPipelineConnect Events. Und wenn ich einen Client abrupt beende, dann wird nichtmals das onDisconnect(INonBlockingPipeline) ausgelöst... Ansich finde ich xSockets wegen diesem Multiplexedsystem ziemlich genial. Aber ich blicke da noch nicht ganz durch. Hat vlt. jemand eine Adresse mit weiteren Infos ? (Bitte nicht die sourceforge seite, da steht nichts wirklich interessantes...)

Gruß, Chris
 
G

grro

Gast
Hallo Chris,

xSocket basiert auf dem Ansatz, dass einer Connection ein Handler zugeordnet wird. Dieser Handler kann dann Callback-Interfaces wie z.B. IConnectHandler oder IDataHandler implementieren. xSocket erkennt über Introspektion diese well-known Interfaces (dass ganze wird dann aus Performancegründe gecach’t, um wiederholte Introspektionen zu vermeiden). Zu einem Zeitpunkt kann einer Connection nur ein Handler zugeordnet sein.

Java:
class MyHandler implements IDataHandler, IConnectHandler {
   
   public boolean onConnect(INonBlockingConnection nbc) throws IOException {
      // …
      return true;
   }
		
   public boolean onData(INonBlockingConnection nbc) throws IOException {
      // ..
      return true;
   }

IServer server = new Server(new MyHandler());
server.start();

Daie Multiplexed lib erweitert xSocket um ein Multiplexing framework. Als Handler wird dann beim Server nicht der „eigentliche“ Handler registriert, sondern der MultiplexedProtocolAdapter.

Java:
IServer server = new Server(new MultiplexedProtocolAdapter(myHdl, multiplexer));
server.start();

Im Konstruktor des Adapters wird dann sowohl der Multiplexer, als auch der eigentliche Handler übergeben. Der Multiplexer implementiert das (De)Multiplexing. Per default (falls nicht gesetzt), wird ein einfacher Multiplexer verwendet.

Der Handler kann sowohl die callback interfaces aus xSocket core implementieren, als auch die callback Interfaces aus der Multiplexing lib. Der Handler ist dann auch nicht mehr der physikalischen tcp connection zugeordnet, sondern einer Pipline, welche einen logischen Kanal auf der tcp connection darstellt. Für die tcp connection ist der MuliplexAdapter verantwortlich, welcher wiederum alle callback Interfaces von xSocket core wie beisielsweise IDataHandler implementiert. D.h. beim Auftreten von Netzwerkevents wird der MultiplexAdapter aufgerufen. Dieser führt das (De)Multiplexing durch, und ruft dann den Handler der betroffenen Pipeline auf. Die speziellen Callback Interfaces der Multiplex lib wie IPipelineDataHandler existieren, damit im Kontext des Handlers nicht nur auf die Pipeline zugegriffen werden kann, sondern auch auf die Management-Funktionalitäten der zugrundeliegenden (Muliplexed) Connection. Anstatt einer INonBlockingConnection wird einem solchen Handler die INonBlockingPipeline übergeben, welche lediglich die INonBlockingConnection um eine zusätzliche Methoden getMultiplexedConnection() erweitert. Mit Hilfe dieser Methode kann dann auf die MuliplexedConnection zugegriffen werden. Typischerweise ist das notwendig, um (server-seitig) neue Pipelines zu öffnen.

Java:
class CommandPipelineHandler implements IPipelineDataHandler {
		
   public boolean onData(INonBlockingPipeline pipeline) throws IOException {
   int cmd = pipeline.readInt();
			
   if (cmd == CMD_NEW_DATA_PIPELINE) {
      IMultiplexedConnection mc = pipeline.getMultiplexedConnection();
				
      String dataPipelineId = connection.createPipeline();
      INonBlockingPipeline dataPipeline = connection.getNonBlockingPipeline(dataPipelineId);
      dataPipeline.setHandler(new DataHandler());

      pipeline.write(dataPipelineId + DELIMITER);
   } else …
      …
   }
}

Das Tutorial bzgl. Multiplexed ist z. Zt. ziemlich dünn. Hast du dir schon die JUnit-Klassen angeschaut? Vielleicht helfen dir diese weiter.

Grüße
Gregor
 

Kr0e

Gesperrter Benutzer
Hallo!

Erstmal danke für die zahlreichen Infos!

Sprich eigentlich müsste ich doch über die Netzwerkevents (IConnectHandler, IDisconnectHandler) benachrichtigt werden, sofern ich dem MultiplexedProtocolAdapter einen IHandler übergebe, der die implementiert, oder ?

Bei mir klappt das nur leider nicht. Um bei deinem Beispiel zu bleiben:

Java:
class MyHandler implements IDisconnectHandler, IConnectHandler, IPipelineConnectHandler, IPipelineDisconnectHandler  {
   
   public boolean onConnect(INonBlockingConnection nbc) throws IOException {
      // … Wird niemals aufgerufen
      return true;
   }
        
   public boolean onConnect(INonBlockingPipeline nbc) throws IOException {
      // … Klappt wunderbar! Neue Pipeline werden hier "eventiert" xD
      return true;
   }

   public boolean onDisconnect(INonBlockingPipeline nbc) throws IOException {
      // … Klappt leider nicht...  (Bzw. bei einem abrupted shutdown des clienten)
      return true;
   }

   public boolean onDisconnect(INonBlockingConnection nbc) throws IOException {
      // … Wird niemals aufgerufen
      return true;
   }
 
IServer server = new Server(new MultiplexedProtocolAdapter(new MyHandler());
server.start();

Nachdem ich mir den Source vom MultiplexedProtocolAdapter angeschaut hab, ist nur aufgefallen,
dass der MultiplexedProtocolAdapter selbst das IConnectHandler-interface managed (Wie du ja bereits schon gesagt hast...)
Sprich es ist unmöglich reele Netzwerkevents zu erhalten neben den Pipelineevents , oder mach ich iwo einen Denkfehler ?

Gruß,
Chris
 
G

grro

Gast
die callback methoden sind alle auf Ebene der Pipeline. D.h. onDisconnect wird aufgerufen wenn die Pipeline geschlossen wird,o der indirekt wenn die MultiplexConnection geschlossen wird. Z.Zt. ist es nicht möglich einen IDisconnectHandler an der MultiplexedConnection zu registrieren (Wurde einfach noch nicht implementiert). Der IConnectHandler und IPipelineConnectHandler sind gleichbedeutend. D.h. wenn identifiziert wird, dass ein IPipelineConnectHandler implementiert wird, wird die Methode von IConnectHandler nicht aufgerufen. Die onDisconnect(INonBlockingPipeline nbc) sollte aufgerufen werden, wenn die Pipeline geschlossen wird. Wenn du einen lauffähigen JUnit-Test hast würde ich die empfehlen diesen an xsocket-develop@lists.sourceforge.net zu senden.

Grüße
Gregor
 

Kr0e

Gesperrter Benutzer
Wenn ich die Verbindung sauber schliesse mit close(), dann wird auch die Pipeline ein onDisconnect senden. Wenn einfach meinen Clienten beende, dann wird dieses Event nicht ausgelöst.

PS: Mir ist grad aufgefallen, dass onDisconnect Events generell nur gesendet werden (Auch komplett ohne den Multiplexed Kram), wenn man con.close() aufruft. Wird ein Programm abrupt beendet, so erfährt das die gegenseite niemals.
 
Zuletzt bearbeitet:
G

grro

Gast
das mit dem disconnect ist so eine Sache. Der onDisconnect call wird immer dann ausgelöst, wenn seitens der JVM signalisiert wird, das die Verbindung beendet wurde. Jedoch gibt es Konstellationen, bei denen ein Verbindungsabruch durch die JVM bzw. der daraunterliegenden originäre Socket API nicht erkannt wird. Das heisst in letzter instanz müssen Daten versendet oder empfangen werden, um sicher zu erkennen, ob die Verbindung terminiert wurde.

Aus diesem Grund ist es sinnvoll mit idle timeouts zu arbeiten. Dem Ansatz liegt der Algorithmus zugrunde, dass wenn nicht innerhalb einer gewissen Zeitspanne Daten empfangen bzw. versendet wurde, die Verbindung invalide ist. Daher bieten die meisten NIO-Frameworks solche eine Idle- bzw. Connection timeout Unterstützung an
 

Kr0e

Gesperrter Benutzer
Hmm, aber NIO z.b. makiert doch einen Channel als lesbar wenn z.b. die Verbindung tot ist. Sollte dann nicht genaugenommen noch ein "onData" ausgelöst werden ?? Damit könnte man dann close() aufrufen und die listener "eventieren"...
 

Kr0e

Gesperrter Benutzer
Ok, eine ganz normale Verbindung sendet doch ein onDisconnect Event. Da war ich zu voreilig beim testen.
Aber Die Pipeline sendet kein onDisconnect wenn die darunter liegende MultiplexedConnection geschlossen wird...

Gruß,
Chris
 

Kr0e

Gesperrter Benutzer
Problem gefunden, könnte evt. ein Bug sein!

In der Datei "MultiplexerConnection" blockiert diese Funktion für immer (Also bis zum Timeout..), falls eine Verbindung beendet wurde (Per Abbruch)
Java:
	private void deregisterPipeline(String pipelineId) throws ClosedChannelException, IOException {
            
		synchronized (multiplexerWriteGuard) {
		    multiplexer.closePipeline(connection, pipelineId); //Wird diese Zeile auskommentiert (Ist natürlich nicht der Sinn der Sache) Funktioniert das onDisconnect Event
		}
                

	}

Vlt. hast du da noch eine Idee wie man das fixen könnte ?

PS: Ich hätte da evt. ne Lösung. Die MultiplexerConnection darf nicht "deregisterPipeline" aufrufen, sofern die Leitung eh tod ist. Dennoch sollte das Event ausgelöst werden... Mal sehen ob ich das irgendwie hinbekomme...

PSS: Das löst das Problem:

Java:
    private void deregisterPipeline(String pipelineId) throws ClosedChannelException, IOException {

        if (isOpen()) {
            synchronized (multiplexerWriteGuard) {
                multiplexer.closePipeline(connection, pipelineId);
            }
        }
    }
 
Zuletzt bearbeitet:
G

grro

Gast
Hallo Chris,

danke für den Hinweis. Möchtest du einen patch an grro der domäne xsocket.org senden? Ich würde dann den fix reviewen, ggfls. einen JUnit-Test erstellen und den fix mergen.

Grüße
Gregor
 

Kr0e

Gesperrter Benutzer
Hi,
ich hab leider grad keine Zeit (Vlt. komme ich morgen dazu), du kannst das ruhig abändern wenn du willst.
Wie gesagt in der Datei "org.xsocket.connection.multiplexed.MultiplexerConnection" die alte Methode "deregisterPipeline"
durch die ersetzen:

Java:
    private void deregisterPipeline(String pipelineId) throws ClosedChannelException, IOException {
 
        if (isOpen()) {
            synchronized (multiplexerWriteGuard) {
                multiplexer.closePipeline(connection, pipelineId);
            }
        }
    }

Gruß,
Chris
 

Neue Themen


Oben