2012-06-01 16 views
6

Estoy usando this tutorial para construir un servidor java nio sin la sección de escritura.Servidor asíncrono con Java NIO

Todo funciona bien, excepto por una cosa interesante:

  • Cuando el cliente está enviando paquetes demasiado rápido, el servidor no recibe todos los mensajes, el servidor está consiguiendo siempre el primero y el segundo paquetes, pero no más que eso.
  • Si el cliente envía los paquetes lentamente, el servidor obtiene todos los paquetes.

¿Alguna idea?

Estoy agregando el código de clase del servidor, si necesita otra clase que se menciona en el código a continuación, estoy aquí :).

clase NIOServer:

package server; 
import java.io.IOException; 
import java.net.InetAddress; 
import java.net.InetSocketAddress; 
import java.net.Socket; 
import java.nio.ByteBuffer; 
import java.nio.channels.SelectionKey; 
import java.nio.channels.Selector; 
import java.nio.channels.ServerSocketChannel; 
import java.nio.channels.SocketChannel; 
import java.nio.channels.spi.SelectorProvider; 
import java.util.*; 

import javax.xml.parsers.ParserConfigurationException; 

import org.xml.sax.SAXException; 

public class NioServer implements Runnable { 



// The host:port combination to listen on 
    private InetAddress hostAddress; 
    private int port; 

    // The channel on which we'll accept connections 
    private ServerSocketChannel serverChannel; 

    // The selector we'll be monitoring 
    private Selector selector; 

    //the cach will hundle the messages that came 
    private Cache cache; 

    // The buffer into which we'll read data when it's available 
    private ByteBuffer readBuffer = ByteBuffer.allocate(8192); 

    public NioServer(InetAddress hostAddress, int port , Cache cache) throws IOException { 
    this.cache = cache; 
    this.hostAddress = hostAddress; 
    this.port = port; 
    this.selector = this.initSelector(); 
    } 


    private Selector initSelector() throws IOException { 
     // Create a new selector 
     Selector socketSelector = SelectorProvider.provider().openSelector(); 

     // Create a new non-blocking server socket channel 
     this.serverChannel = ServerSocketChannel.open(); 
     serverChannel.configureBlocking(false); 

     // Bind the server socket to the specified address and port 
     InetSocketAddress isa = new InetSocketAddress(this.hostAddress, this.port); 
     serverChannel.socket().bind(isa); 

     // Register the server socket channel, indicating an interest in 
     // accepting new connections 
     serverChannel.register(socketSelector, SelectionKey.OP_ACCEPT); 

     return socketSelector; 
     } 

    private void accept(SelectionKey key) throws IOException { 
     // For an accept to be pending the channel must be a server socket channel. 
     ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel(); 

     // Accept the connection and make it non-blocking 
     SocketChannel socketChannel = serverSocketChannel.accept(); 
     Socket socket = socketChannel.socket(); 
     socketChannel.configureBlocking(false); 

     // Register the new SocketChannel with our Selector, indicating 
     // we'd like to be notified when there's data waiting to be read 
     socketChannel.register(this.selector, SelectionKey.OP_READ); 
     } 

    private void read(SelectionKey key) throws IOException { 
     SocketChannel socketChannel = (SocketChannel) key.channel(); 

     // Clear out our read buffer so it's ready for new data 
     this.readBuffer.clear(); 

     // Attempt to read off the channel 
     int numRead; 
     try { 
      numRead = socketChannel.read(this.readBuffer); 
      String test = new String(this.readBuffer.array()); 
      System.out.print(test); 

     } catch (IOException e) { 
      // The remote forcibly closed the connection, cancel 
      // the selection key and close the channel. 
     // key.cancel(); 
     // socketChannel.close(); 
      return; 
     } 

     if (numRead == -1) { 
      // Remote entity shut the socket down cleanly. Do the 
      // same from our end and cancel the channel. 
      key.channel().close(); 
      key.cancel(); 
      return; 
     } 

     // Hand the data off to our worker thread 
     this.cache.processData(this, socketChannel, this.readBuffer.array(), numRead); 
     } 

    public void run() { 
     while (true) { 
      try { 
      // Wait for an event one of the registered channels 

      this.selector.select(); 



      // Iterate over the set of keys for which events are available 
      Iterator selectedKeys = this.selector.selectedKeys().iterator(); 
      while (selectedKeys.hasNext()) { 
       SelectionKey key = (SelectionKey) selectedKeys.next(); 
       selectedKeys.remove(); 

       if (!key.isValid()) { 
       continue; 
       } 

       // Check what event is available and deal with it 
       if (key.isAcceptable()) { 
       this.accept(key); 
       } else if (key.isReadable()) { 
       this.read(key); 
       } 
      } 
      } catch (Exception e) { 
      e.printStackTrace(); 
      } 
     } 
     } 

    public static void main(String[] args) throws ParserConfigurationException, SAXException { 
    try { 
     Cache cache = new Cache(); 
     new Thread(cache).start(); 
     new Thread(new NioServer(null, 9090,cache)).start(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    } 
+3

Debe haber un error en su código. Si quieres más ayuda, danos más información. –

+0

No tengo el código ahora, lo tendré el domingo. Gracias –

+3

TCP no pierde datos y tampoco lo hace NIO. No está leyendo todos los datos o tirando algunos de ellos. Sin algún código para comentar es imposible hacer más comentarios. – EJP

Respuesta

1

yo esperaría que si leías UDP. Tenga en cuenta qué tan lento está procesando sus paquetes en el método read. Está imprimiéndolos en system.out, que es muy lento y no está seguro de qué tan rápido puede manejar los datos al otro hilo en el método processData. This library que escribí pueden ayudarte a hacer una comunicación sin bloqueo entre hilos si esa es la fuente de tu retraso. También debe verificar el tamaño de su buffer de lectura de socket subyacente. Cuanto más grande es, más espacio tienes que ser rápido y ponerte al día antes de que los paquetes comiencen a soltarse. Para TCP, probablemente obtenga una IOException en el canal si el buffer de socket subyacente se llena. Para UDP, los paquetes se eliminan silenciosamente.

Para tener acceso al tamaño del búfer de lectura socket subyacente que puede hacer:

final Socket socket = channel.socket(); 
System.out.println(socket.getReceiveBufferSize()); 
socket.setReceiveBufferSize(newSize); 

Nota: Que yo sepa, Linux podría requerir alguna configuración del sistema operativo con el fin de cambiar el tamaño del búfer subyacente. Si el setReceiveBufferSize no tiene ningún efecto (léelo de nuevo para ver si se modificó), google al respecto. :)

Cuestiones relacionadas