2

我正在编写一个基于java的聊天服务器,目前我的设计基于以下内容:-当聊天室中的一个人发送消息时,服务器端的聊天室类会循环向房间中的每个参与者发送相同的消息. 显然,这是一个糟糕的设计,因为网络调用是在循环中对单个参与者进行的。因此,例如,假设聊天室中有 10 个人。当一个用户发送消息时,聊天室类将循环发送相同的消息给所有 10 个人。如果说,循环中的第五个人的连接很糟糕,那么第六个人..第十个人看到消息的时间就会受到影响。

如果我从每个房间的单播转移到多播,那么我如何获得每个聊天室的私人多播组 ip?此外,每个聊天室都有单独的群组似乎有点过头了。主要问题之一是当我通过循环回复房间中的用户时,通过套接字连接发送数据的方法被阻塞。因此,我在想如果我使用非阻塞 NIO 套接字,然后将消息循环发送给接收者,那会解决问题吗?是否有其他巧妙的技巧可以优化向房间内接收者发送数据?

4

3 回答 3

4

简单的实现是每个客户端使用两个线程。一个线程从套接字读取另一个线程写入套接字。如果您的客户很少,这会很好。您必须了解 NIO 才能处理许多客户。(当线程模型不能很好地工作时,“很多”的意思。)

客户端的读取线程从套接字读取整条消息并将其放入 ChatRoom 对象中的队列中。聊天室有一个线程将消息从队列中取出并将它们放入客户端的队列中。客户端写入线程轮询其队列并将消息写入套接字。

ChatRoom 有一个线程来接受连接并创建客户端对象并将它们放入一个集合中。它有另一个线程来轮询其消息队列并将消息分发到客户端队列。

Apache Mina有一个使用 NIO 的示例

于 2009-07-20T04:51:02.127 回答
2

我同意连续循环你的收件人是个坏主意。为此,您可以考虑使用 ThreadPool 来提供帮助。但是,我认为多播将是您最好的选择。它非常适合聊天室模型。您只需要发送一次,您的迭代方法就会得到解决。您可以通过在地址中指定不同的端口来获得唯一的组 ID。

于 2009-07-20T04:51:22.593 回答
2

简单的方法是每个客户端连接使用两个线程。一个线程处理从客户端读取消息,另一个用于发送消息,从而可以同时发送/接收来自客户端的消息。

为了避免在循环客户端连接以广播消息时进行网络调用,服务器线程应将消息添加到队列中以发送给客户端。java.util.concurrent 中的 LinkedBlockingQueue 非常适合这一点。下面是一个例子:

/**
 * Handles outgoing communication with client
 */
public class ClientConnection extends Thread {
    private Queue<String> outgoingMessages = new LinkedBlockingQueue<String>(MAX_OUTGOING);
    // ...
    public void queueOutgoing(String message) {
        if (!outgoingMessages.offer(message)) {
            // Kick slow clients
            kick();
        }
    }

    public void run() {
        // ...
        while (isConnected) {
            List<String> messages = new LinkedList<String>();
            outgoingMessages.drainTo(messages);
            for (String message : messages) {
                send(message);
            }
            // ...
        }
    }
}

public class Server {
    // ...
    public void broadcast(String message) {
        for (ClientConnection client : clients) {
            client.queueOutgoing(message);
        }
    }
}
于 2009-07-20T05:41:03.303 回答