问题描述
我正在编写一组客户端/服务器程序
I am writing a Client/Server set of programs
根据客户端请求的操作,我使用make TCP或UDP请求。
Depending on the operation requested by the client, I use make TCP or UDP request.
实现客户端是直接的,因为我可以轻松地打开与任何协议的连接并将请求发送到服务器端。
Implementing the client side is straight-forward, since I can easily open connection with any protocol and send the request to the server-side.
另一方面,在服务器端,我想在同一端口上同时监听UDP和TCP连接。而且,我喜欢服务器为每个连接请求打开新线程。
On the servers-side, on the other hand, I would like to listen both for UDP and TCP connections on the same port. Moreover, I like the the server to open new thread for each connection request.
我采用了以下解释的方法:
I have adopted the approach explained in: link text
我通过为每个TCP / UDP请求创建新线程来扩展此代码示例。
I have extended this code sample by creating new threads for each TCP/UDP request.
如果我只使用TCP,这可以正常工作,但是当我尝试进行UDP绑定时它会失败。
This works correctly if I use TCP only, but it fails when I attempt to make UDP bindings.
请给我任何建议我可以纠正这个。
Please give me any suggestion how can I correct this.
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<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);
}
}
}
UDPThread代码:
The UDPThread code:
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)
10x
推荐答案
它应该有效。看起来,这个代码的一个问题是ByteBuffer大小设置为0,这意味着数据报被丢弃(正如在注释中提到的那样)。如果您需要通过UDP接收任何信息,并且您在可靠的网络上,则可以设置相当大的大小并接收由多个数据包组成的大数据报。否则,在不可靠的网络上,将其设置为MTU大小。确保在收到ByteBuffer中的任何内容后翻转()。
It should work. One of the problems with this code, it seems, is that the ByteBuffer size is set to 0, meaning that the datagram is discarded (as it mentions in the comments). If you need to receive any information over UDP and you are on a reliable network, you can set the size quite big and receive big datagrams made up of multiple packets. Otherwise, on an unreliable network, set this to the MTU size. Make sure you flip() the ByteBuffer after receiving anything in it.
此外,为每个请求创建新线程是一个坏主意,为每个请求创建一个会话线程您在HashMap或其他东西中收到的不同IP,然后执行。在传递新信息后收到消息时,唤醒睡在该对象上的线程。您拥有的选择器代码旨在以这种方式避免创建线程。
Also, creating new threads for each request is a bad idea, create a 'session' thread for each different IP you receive in a HashMap or something, and then do a guarded block on the session object. Wake up the thread sleeping on that object when you receive a message after passing in new information. The selector code you have is designed to avoid the creation of threads in this way.
编辑:根据上面的代码,你是创建一个数据报通道,然后使用套接字直接接收数据报?这没有意义。仅在绑定通道后才使用通道方法。另外,不要在单独的线程中执行此操作。您的代码不是线程安全的,并且会破坏自己。如前所述,将收到的信息传递给单独的会话线程。选择器旨在告诉您可以不阻塞地读取哪些通道(尽管阻塞已被禁用,因此它将告诉您哪些通道有数据可供读取)。
based on the above code, you're create a datagram channel and then using the socket to receive datagrams directly? That's doesn't make sense. Use the channel methods only after binding the channel. Also, don't do this in a separate thread. Your code isn't thread-safe and will bust itself up. Hand the received information off to the separate 'session' thread as mentioned earlier. The selector is designed to tell you what channels can be read from without blocking (although blocking is disabled anyway, so it will tell you what channels have data to be read from).
这篇关于在同一端口上侦听TCP和UDP请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!