如何在 Java 中实现基于线程 UDP 的服务器?

发布于 2024-07-17 18:07:57 字数 527 浏览 5 评论 0原文

如何在 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 编程之父们请帮忙。

How can I implement a threaded UDP based server in Java ?

Basically what I want, is to connect multiple clients to the server, and let each client have his own thread. The only problem is, that I don't know how to check if a client is trying to connect to the server and spawn a new thread for it.

boolean listening = true;

System.out.println("Server started.");

while (listening)
    new ServerThread().start();

In this case the server will spawn new threads until it runs out of memory.
Here's the code for the ServerThread ( I think I need here a mechanism that stalls the creation of the ServerThread until a client tries to connect.

public ServerThread(String name) throws IOException 
{
    super(name);
    socket = new DatagramSocket();
}

So fathers of Java programming please help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

岁月静好 2024-07-24 18:07:58

这种设计在一定程度上取决于每个完整的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);
    }
}

The design for this to a certain extent depends on whether each complete UDP "dialog" just requires a single request and immediate response, whether it's a single request or response with retransmissions, or whether there'll be a need to process lots of packets for each client.

The RADIUS server I wrote had the single request + retransmit model and spawned a thread for each incoming packet.

As each DatagramPacket was received it was passed to a new thread, and then that thread was responsible for sending back the response. This was because the computation and database accesses involved in generating each response could take a relatively long time and it's easier to spawn a thread than to have some other mechanism to handle new packets that arrive whilst old packets are still being processed.

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);
    }
}
暗藏城府 2024-07-24 18:07:58

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

Since UDP is a connectionless protocol, why do you need to spawn a new thread for each connection? When you receive a UDP packet maybe you should spawn a new thread to take care of dealing with the message received.

UDP connections are not like TCP connections. They do not remain active and such is the design of UDP.

The handlePacket() method of this next code block can do whatever it wants with the data received. And many clients can send multiple packets to the same UDP listener. Maybe it will help you.

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() );
            }
        }
    }
怂人 2024-07-24 18:07:58

您看过 Apache Mina 项目吗? 我相信即使是其中的一个示例也会引导您了解如何使用它设置基于 UDP 的服务器。 如果这是一个真正的产品,我不建议尝试从头开始提出自己的实现。 您将需要使用一个库来完成此任务,因此您为每个连接使用一个线程,而是使用线程池。

Have you looked at the Apache Mina project? I believe even one of its examples takes you through how to setup an UDP-based server with it. If this for a real product, I would not recommend trying to come up with your own implementation from scratch. You will want to use a library to accomplish this so you are not using one thread per connection, rather a thread pool.

〃安静 2024-07-24 18:07:58

我真的不认为有必要。

这是学校的事情吧?

如果您需要跟踪客户端,则应该有每个客户端的本地表示(服务器上的 Client 对象)。 它可以处理您需要做的任何特定于客户的事情。

在这种情况下,您需要能够找出消息是从哪个客户端发送的。 (使用消息中的信息。)您可以将客户端保留在地图中。

最有效的方法可能是在主线程中进行所有处理,除非需要完成的任何操作都可以“阻止”等待外部事件(或者如果某些应该发生的事情可能需要很长时间,而有些事情可能需要很短的时间)。 )

public class Client {

    public void handleMessage(Message m) {
    // do stuff here.
    }

}

如果需要的话,客户端对象也许可以在handleMessage() 中启动一个新线程。

您不应该启动多个服务器线程。

服务器线程可以执行以下操作:

while(running) {
  socket.receive(DatagramPacket p);
  client = figureOutClient(p);
  client.handleMessage(p);
}

如果没有需要关心的特定于客户端的事情,只需在一个线程中读取消息并在消息到达时对其进行处理。

I don't really see the need.

Its a school thing right?

If you need to keep track of the clients, you should have a local representation of each client (a Client object on your server). It can take care of whatever client-specific things you need to do.

In that case You need to be able to find out from which client the message was sent from. (using information from the message.) You can keep the clients in a map.

The most effective way is probably to do all handling in the main thread, unless whatever that needs to be done can "block" waiting for external events (or if some things that's supposed to happen might take a long time and some a very short.)

public class Client {

    public void handleMessage(Message m) {
    // do stuff here.
    }

}

The client object can perhaps start a new thread in handleMessage() if neccesary.

You shouldn't start multiple server threads.

The server thread can do:

while(running) {
  socket.receive(DatagramPacket p);
  client = figureOutClient(p);
  client.handleMessage(p);
}

If there are no client-specific things to care about, just read the messages and handle them as they arrive, in one thread.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文