2010-05-12 33 views
7

Estoy escribiendo un conjunto de cliente/servidor de programaspara TCP y UDP solicitudes en el mismo puerto

Dependiendo de la operación solicitada por el cliente, hacer uso de TCP o UDP solicitud.

La implementación del lado del cliente es sencilla, ya que puedo abrir fácilmente la conexión con cualquier protocolo y enviar la solicitud al lado del servidor.

En el lado del servidor, por otro lado, me gustaría escuchar conexiones UDP y TCP en el mismo puerto. Además, me gusta que el servidor abra un nuevo hilo para cada solicitud de conexión.

he adoptado el enfoque se explica en: link text

He ampliado este ejemplo de código mediante la creación de nuevos temas para cada solicitud de TCP/UDP.

Esto funciona correctamente si utilizo solo TCP, pero falla cuando intento hacer enlaces UDP.

Por favor, dame cualquier sugerencia sobre cómo puedo corregir esto.

TNX

Este es el código del servidor:

public class Server { 
public static void main(String args[]) { 
    try { 
     int port = 4444; 
     if (args.length > 0) 
      port = Integer.parseInt(args[0]); 

     SocketAddress localport = new InetSocketAddress(port); 

     // Create and bind a tcp channel to listen for connections on. 
     ServerSocketChannel tcpserver = ServerSocketChannel.open(); 
     tcpserver.socket().bind(localport); 

     // Also create and bind a DatagramChannel to listen on. 
     DatagramChannel udpserver = DatagramChannel.open(); 
     udpserver.socket().bind(localport); 

     // Specify non-blocking mode for both channels, since our 
     // Selector object will be doing the blocking for us. 
     tcpserver.configureBlocking(false); 
     udpserver.configureBlocking(false); 

     // The Selector object is what allows us to block while waiting 
     // for activity on either of the two channels. 
     Selector selector = Selector.open(); 

     tcpserver.register(selector, SelectionKey.OP_ACCEPT); 
     udpserver.register(selector, SelectionKey.OP_READ); 

     System.out.println("Server Sterted on port: " + port + "!"); 

     //Load Map 
     Utils.LoadMap("mapa"); 
     System.out.println("Server map ... LOADED!"); 

     // Now loop forever, processing client connections 
     while(true) { 
      try { 
       selector.select(); 
       Set<SelectionKey> keys = selector.selectedKeys(); 

       // Iterate through the Set of keys. 
       for (Iterator<SelectionKey> i = keys.iterator(); i.hasNext();) { 
        SelectionKey key = i.next(); 
        i.remove(); 

        Channel c = key.channel(); 

        if (key.isAcceptable() && c == tcpserver) { 
         new TCPThread(tcpserver.accept().socket()).start(); 
        } else if (key.isReadable() && c == udpserver) { 
         new UDPThread(udpserver.socket()).start(); 
        } 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
     System.err.println(e); 
     System.exit(1); 
    } 
} 

}

El código UDPThread:

public class UDPThread extends Thread { 
private DatagramSocket socket = null; 

public UDPThread(DatagramSocket socket) { 
    super("UDPThread"); 
    this.socket = socket; 
} 

@Override 
public void run() { 
    byte[] buffer = new byte[2048]; 
    try {   
     DatagramPacket packet = new DatagramPacket(buffer, buffer.length); 
     socket.receive(packet); 

     String inputLine = new String(buffer); 
     String outputLine = Utils.processCommand(inputLine.trim()); 

     DatagramPacket reply = new DatagramPacket(outputLine.getBytes(), outputLine.getBytes().length, 
                packet.getAddress(), packet.getPort()); 
     socket.send(reply); 

    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    socket.close(); 
} 

}

recibo:

Exception in thread "UDPThread" java.nio.channels.IllegalBlockingModeException 
at sun.nio.ch.DatagramSocketAdaptor.receive(Unknown Source) 
at server.UDPThread.run(UDPThread.java:25) 

10x

+0

¿Cómo funciona? ¿Tiene más información, como mensajes de error o código de muestra? –

+0

Por favor, elabore "falla" en más detalle. – BalusC

Respuesta

0

yo sepa, debe ser capaz de escuchar tanto para las conexiones TCP y UDP mensajes en el mismo puerto. Ayudaría si publicaras tu código UDP y la excepción + stacktrace que estás viendo.

3

Debería funcionar. Parece que uno de los problemas con este código es que el tamaño de ByteBuffer está establecido en 0, lo que significa que el datagrama se descarta (como se menciona en los comentarios). Si necesita recibir información sobre UDP y está en una red confiable, puede establecer un tamaño bastante grande y recibir grandes datagramas formados por múltiples paquetes. De lo contrario, en una red no confiable, establezca esto en el tamaño de MTU. Asegúrese de voltear() el ByteBuffer después de recibir cualquier cosa en él.

Además, la creación de nuevos subprocesos para cada solicitud es una mala idea, cree una secuencia de "sesión" para cada IP diferente que reciba en un HashMap o algo así, y luego haga un guarded block en el objeto de sesión. Despierta el hilo que duerme en ese objeto cuando recibes un mensaje después de pasar información nueva. El código de selector que tiene está diseñado para evitar la creación de hilos de esta manera.

Edición: basado en el código anterior, ¿está creando un canal de datagrama y luego usando el socket para recibir datagramas directamente? Eso no tiene sentido. Use los métodos de canal solo después de vincular el canal. Además, no hagas esto en un hilo separado. Su código no es seguro para subprocesos y se destruirá a sí mismo. Entregue la información recibida a la secuencia de 'sesión' separada como se mencionó anteriormente.El selector está diseñado para decirle qué canales se pueden leer sin bloquear (aunque el bloqueo está desactivado de todos modos, por lo que le dirá qué canales tienen datos para leer).

+0

Puedo ver su punto con el uso del hilo de la sesión, estoy de acuerdo con usted, pero para mi propósito, es mejor hacer un hilo por conexión. para el ByteBuffer, no lo uso parece que no vio el código que he cargado, solo el enlace. tnx – msaveski

+0

Los sockets UDP no tienen conexiones. Solo los sockets TCP lo hacen. El hilo simplemente mantiene el procesamiento alejado del hilo de selección principal. De todos modos, así es como funciona Apache MINA :) –

+0

Aham, si te entendí bien, dices que no tiene sentido crear un nuevo hilo UDP, sino más bien recibir la información en la clase de servidor y eso, procesarlo en un nuevo hilo ? BTW, ¿hay alguna forma más elegante de hacer lo mismo, escuchar las solicitudes de tcp y udp? – msaveski

0

No puede usar DatagramSocket.receive() en modo no bloqueante. Debe utilizar los métodos read() o de su DatagramChannel directamente.

Cuestiones relacionadas