如何在Java中实现基于线程的UDP服务器?
基本上我想要的是将多个客户端连接到服务器,并让每个客户端都有自己的线程。唯一的问题是,我不知道如何检查客户端是否正在尝试连接到服务器并为其生成新线程。
boolean listening = true;
System.out.println("Server started.");
while (listening)
new ServerThread().start();
在这种情况下,服务器将生成新线程,直到内存不足为止。 这是ServerThread的代码(我想我需要一种机制,在客户端尝试连接之前停止创建ServerThread。
public ServerThread(String name) throws IOException
{
super(name);
socket = new DatagramSocket();
}
所以Java编程的父亲请帮忙。
答案 0 :(得分:14)
这在一定程度上的设计取决于每个完整的UDP“对话框”是否只需要一个请求和立即响应,无论是单个请求还是具有重传的响应,或者是否需要处理批次每个客户端的数据包。
我写的RADIUS服务器有单个请求+重传模型,并为每个传入的数据包生成一个线程。
当收到每个DatagramPacket
时,它被传递给一个新线程,然后该线程负责发回响应。这是因为生成每个响应所涉及的计算和数据库访问可能需要相对较长的时间,并且产生一个线程比使用其他机制来处理在旧数据包仍处理时到达的新数据包更容易。
public class Server implements Runnable {
public void run() {
while (true) {
DatagramPacket packet = socket.receive();
new Thread(new Responder(socket, packet)).start();
}
}
}
public class Responder implements Runnable {
Socket socket = null;
DatagramPacket packet = null;
public Responder(Socket socket, DatagramPacket packet) {
this.socket = socket;
this.packet = packet;
}
public void run() {
byte[] data = makeResponse(); // code not shown
DatagramPacket response = new DatagramPacket(data, data.length,
packet.getAddress(), packet.getPort());
socket.send(response);
}
}
答案 1 :(得分:6)
由于UDP是无连接协议,为什么需要为每个连接生成一个新线程?当您收到UDP数据包时,您可能会生成一个新线程来处理收到的消息。
UDP连接与TCP连接不同。它们不会保持活动状态,这就是UDP的设计。
下一个代码块的handlePacket()方法可以对接收到的数据执行任何操作。许多客户端可以将多个数据包发送到同一个UDP侦听器。也许它会帮助你。
public void run() {
DatagramSocket wSocket = null;
DatagramPacket wPacket = null;
byte[] wBuffer = null;
try {
wSocket = new DatagramSocket( listenPort );
wBuffer = new byte[ 2048 ];
wPacket = new DatagramPacket( wBuffer, wBuffer.length );
} catch ( SocketException e ) {
log.fatal( "Could not open the socket: \n" + e.getMessage() );
System.exit( 1 );
}
while ( isRunning ) {
try {
wSocket.receive( wPacket );
handlePacket( wPacket, wBuffer );
} catch ( Exception e ) {
log.error( e.getMessage() );
}
}
}
答案 2 :(得分:3)
你看过Apache Mina项目了吗?我相信即使其中一个例子也会向您介绍如何使用它设置基于UDP的服务器。如果这是一个真正的产品,我不建议尝试从头开始提出自己的实现。您将需要使用库来实现此目的,因此您不每个连接使用一个线程,而不是线程池。
答案 3 :(得分:1)
我真的没有看到需要。
这是学校的事吗?
如果需要跟踪客户端,则应该具有每个客户端的本地表示形式(服务器上的客户端对象)。它可以处理您需要做的任何客户特定的事情。
在这种情况下,您需要能够找出发送消息的客户端。 (使用消息中的信息。)您可以将客户端保存在地图中。
最有效的方法可能是在主线程中进行所有处理,除非需要做的任何事情可以“阻止”等待外部事件(或者如果某些事情发生可能需要很长时间而且有些很短。)
public class Client {
public void handleMessage(Message m) {
// do stuff here.
}
}
如果需要,客户端对象可以在handleMessage()中启动一个新线程。
您不应该启动多个服务器线程。
服务器线程可以:
while(running) {
socket.receive(DatagramPacket p);
client = figureOutClient(p);
client.handleMessage(p);
}
如果没有特定于客户端的事情需要关注,只需阅读消息并在一个帖子中处理它们。