para - sockets en java cliente servidor netbeans
Escuchar solicitudes TCP y UDP en el mismo puerto (3)
AFAIK, debería poder escuchar tanto las conexiones TCP como los mensajes UDP en el mismo puerto. Ayudaría si publicaras tu código UDP y la excepción + stacktrace que estás viendo.
Estoy escribiendo un conjunto de programas Cliente / Servidor
Dependiendo de la operación solicitada por el cliente, utilizo la solicitud TCP o UDP.
Implementar el lado del cliente es sencillo, ya que puedo abrir fácilmente la conexión con cualquier protocolo y enviar la solicitud al lado del servidor.
Por 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 explicado en: texto del enlace
He extendido este ejemplo de código creando nuevos subprocesos 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
Aquí está 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 UDPhhread:
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
Deberia de 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 bloque protegido en el objeto de la sesión. Despierte el hilo que duerme en ese objeto cuando recibe 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 subprocesos de esta manera.
Editar: basado en el código anterior, ¿estás 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).
No puede usar DatagramSocket.receive()
en modo no bloqueante. Debe usar los métodos de read()
o receive()
de su DatagramChannel
directamente.