2010-04-21 5 views
5

Ich versuche Java zu lernen. Ich möchte ein einfaches vernetztes Connect 4-Spiel sowie eine Chat-Funktion implementieren.Java ServerSocketChannel SocketChannel (Rückruf)

Ich möchte, dass meine Netzwerklogik nicht blockiert ist. Nach vielen Studien habe ich herausgefunden, dass SocketChannel genau das ist, was ich nach meiner Neustrukturierung bin.

Was noch keinen Sinn gemacht hat ist das Fehlen von CallBack Funktionen in SocketChannels .. Wie man in C# findet.

Meine Abfrage für diese Zeit ist: Wie übermittle ich die empfangenen Daten zum Chat oder Spielformular (JFrame)?

Einige Hinweise sind sehr willkommen.

+0

Ich schlage vor, dass Sie mehrere Thread anstelle von nicht blockierenden E/A verwenden. –

Antwort

13

Sie müssen einen Selektor verwenden. Zuerst eine Selector erstellen, um die Ereignisse zu empfangen:

Selector selector = Selector.open() 

Dann müssen Sie die ServerSocketChannel mit dem Wahlregister:

SelectionKey acceptKey = server.register(selector, SelectionKey.OP_ACCEPT); 

Dann müssen Sie den Selector verwenden, um Ereignisse zu verarbeiten, wie sie kommen in (Sie denken kann dies als „Callback“ Teil des Prozesses:

while(true){ 
    //how many channel keys are available 
    int available = selector.select(); 
    //select is blocking, but should only return if available is >0, this is more of a sanity check 
    if(available == 0) continue; 

    Iterator<SelectionKey> keys = selector.selectedKeys().iterator(); 
    while(keys.hasNext()){ 
    SelectionKey key = keys.next(); 
    keys.remove(); 
    //someone is trying to connect to the server socket 
    if(key.isAcceptable()) doAccept(key); 
    //someone is sending us data 
    else if(key.isReadable()) doRead(key); 
    //we are trying to (and can) send data 
    else if(key.isWritable()) doWrite(key); 
} 

das Fleisch in doAccept sein wird(), doRead() und doWrite() Für eine Auswahltaste Taste akzeptieren die inf enthalten. um den neuen Socket zu erstellen.

doAccept(SelectionKey key){ 

//create the new socket 
SocketChannel socket = ((ServerSocketChannel)key.channel()).accept(); 
//make it non-blocking as well 
socket.configureBlocking(false); 

... 
//here you would likely have some code to init your game objects/communication protocol, etc. and generate an identifier object (used below). 
//and be able to find the socket created above 
... 

//Since it is non blocking it needs a selector as well, and we register for both read and write events 
SelectionKey socketKey = socket.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE); 
// so we can identify the events as they come in 
socketKey.attach(someSocketIndentifier); 
} 

Die letzte Zeile fügt den Schlüssel einen Gegenstand so, dass die Ereignisse vom Selektor empfangen können auf eine Verbindung zurückgeführt werden (zum Beispiel könnte es ein Spieler im Spiel sein). Jetzt können Sie neue Verbindungen akzeptieren und Sie müssen nur lesen und schreiben.

doRead(SelectionKey key){ 
    //here we retrieve the key we attached earlier, so we now what to do/wheer the data is coming from 
    MyIdentifierType myIdentifier = (MyIdentifierType)key.attachment(); 
    //This is then used to get back to the SocketChannel and Read the Data 
    myIdentifier.readTheData(); 
} 

in ähnlicher Weise für Schreib

doWrite(SelectionKey key){ 
    //here we retrieve the key we attached earlier, so we now what to do/wheer the data is coming from 
    MyIdentifierType myIdentifier = (MyIdentifierType)key.attachment(); 
    //This is then used to get back to the SocketChannel and Read the Data 
    myIdentifier.getSocketHandler().writePendingData(); 
} 

Lesen ist ziemlich einfach, man muss nur ein ByteBuffer erstellen und rufen Sie dann die SocketChannels lesen (ByteBuffer) (oder einer seiner Varianten) die Daten zu erhalten, bereit, sich auf der Kanal bis er leer ist.

Schreiben ist ein bisschen schwieriger, wie Sie in der Regel die Daten geschrieben werden sollen, puffern wollen, bis Sie das Schreibereignis empfangen:

class MyNetworkClass{ 
    ByteBuffer writeBuffer = ByteBuffer.allocate(1024); 
    SocketChannel commchannel; //from the server accept processing 

    ... 

    public void write(byte[] data){ 
    //here the class writeBuffer object is filled with the data 
    //but it isn't actually sent over the socket 
    ... 
    } 

    public void writePendingData(){ 
    //here actually write the data to the socket 
    commchannel.write(writeBuffer); 
    } 
} 

Beachten Sie, dass Sie über die entsprechenden Code verwalten den Puffer in der Klasse müssen in Das Ereignis wird voll, oder es wird in der Write Pending-Methode entsprechend geändert, wenn nicht alle Daten im Puffer in den Socket geschrieben werden, sowie die verschiedenen Ausnahmen, die während des Prozesses ausgelöst werden können. Hoffe, das hilft dir beim Einstieg.

+0

Das war sehr nützlich, ich verstehe den Prozess jetzt besser. – iTEgg