在同一端口上侦听TCP和UDP请求

我正在编写一组Client / Server程序

根据客户端请求的操作,我使用make TCP或UDP请求。

实现客户端是直截了当的,因为我可以轻松地打开与任何协议的连接并将请求发送到服务器端。

另一方面,在服务器端,我想在同一端口上同时监听UDP和TCP连接。 而且,我喜欢服务器为每个连接请求打开新线程。

我采用了以下解释的方法: 链接文本

我通过为每个TCP / UDP请求创建新线程来扩展此代码示例。

如果我只使用TCP,这可以正常工作,但是当我尝试进行UDP绑定时它会失败。

请给我任何建议如何纠正这个问题。

TNX

这是服务器代码:

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 keys = selector.selectedKeys(); // Iterate through the Set of keys. for (Iterator 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); } } 

}

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

}

我收到:

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

10倍

它应该工作。 看起来,这个代码的一个问题是ByteBuffer大小设置为0,这意味着数据报被丢弃(正如在注释中提到的那样)。 如果您需要通过UDP接收任何信息,并且您在可靠的网络上,则可以设置相当大的大小并接收由多个数据包组成的大数据报。 否则,在不可靠的网络上,将其设置为MTU大小。 确保在接收到任何内容后翻转()ByteBuffer。

此外,为每个请求创建新线程是一个坏主意,为您在HashMap或其他东西中收到的每个不同的IP创建一个“会话”线程,然后对会话对象执行保护阻止 。 在传递新信息后收到消息时,唤醒睡在该对象上的线程。 您拥有的选择器代码旨在避免以这种方式创建线程。

编辑:根据上面的代码,你创建一个数据报通道,然后使用套接字直接接收数据报? 这没有意义。 仅在绑定通道后才使用通道方法。 另外,不要在单独的线程中执行此操作。 您的代码不是线程安全的,并且会破坏自己。 如前所述,将收到的信息传递给单独的“会话”线程。 选择器旨在告诉您可以不阻塞地读取哪些通道(尽管阻塞已被禁用,因此它将告诉您哪些通道有数据要读取)。

AFAIK,您应该能够在同一端口上侦听TCP连接和UDP消息。 如果您发布了UDP代码,以及您看到的exception+堆栈跟踪,这将有所帮助。

您不能在非阻塞模式下使用DatagramSocket.receive() 。 您必须直接使用DatagramChannelread()receive()方法。

实际上,当您使用非阻塞模式和Selector ,很难UDPThread为什么您还使用UDPThread 。 只需调用udpserver.receive()而不是启动线程。