2010-04-21 9 views
5

Estoy tratando de aprender Java. Me gustaría implementar un simple juego connect 4 en red, así como una función de chat.Java ServerSocketChannel SocketChannel (Devolución de llamada)

Quiero que la lógica de mi red no sea bloqueante, así que después de mucho estudiar, descubrí que SocketChannel es lo que busco después de haber reorientado mis necesidades.

Lo que todavía no tiene sentido es la falta de funciones de CallBack en SocketChannels .. Al igual que uno encuentra en C#.

Mi consulta para este momento es: ¿Cómo envío los datos recibidos al formulario de Chat o Juego (JFrame)?

Alguna orientación es bienvenida.

+0

Sugiero que use múltiples hilos en lugar de E/S sin bloqueo. –

Respuesta

13

Necesita usar un Selector. En primer lugar crear un selector para recibir los eventos:

Selector selector = Selector.open() 

Luego hay que registrar el ServerSocketChannel con el selector:

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

Luego hay que utilizar el selector para procesar los eventos a medida que llegan (se puede pensar en esto como la parte de "devolución de llamada" del proceso:

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); 
} 

la carne estará en doAccept(), doRead(), y doWrite() Para una tecla aCEPTAR la tecla de selección contendrá el inf. ormación para crear el nuevo Socket.

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); 
} 

La última línea agrega un objeto a la clave para que los eventos recibidos desde el selector se puede atribuir a una conexión (por ejemplo, podría ser un jugador en el juego). Así que ahora puedes aceptar nuevas conexiones y solo necesitarás leer y escribir.

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(); 
} 

de manera similar para escribir

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(); 
} 

lectura es bastante sencillo, que acaba de crear un ByteBuffer y luego llamar a los SocketChannels leen (ByteBuffer) (o una de sus variantes) para obtener los datos de lista de el canal hasta que esté vacío.

La escritura es un poco más complicado ya que es probable que desee para amortiguar los datos a escribir hasta que reciba el evento de escritura:

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); 
    } 
} 

Tenga en cuenta que necesitará código apropiado para gestionar la memoria intermedia en la clase de el evento se llena, o modificarlo apropiadamente en el método de escritura pendiente si no todos los datos en el búfer se escriben en el zócalo, así como las diversas excepciones que se pueden lanzar durante el proceso. Espero que esto te ayude a comenzar.

+0

Esto ha sido muy útil, ahora entiendo mejor el proceso. – iTEgg

Cuestiones relacionadas