Java聊天服务器

时间:2009-07-20 04:01:04

标签: java networking network-programming chat

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

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

3 个答案:

答案 0 :(得分:3)

简单的实现是每个客户端使用两个线程。一个线程从套接字读取另一个线程写入套接字。如果您的客户很少,那就没问题了。您必须了解NIO才能处理许多客户。 ('很多'意味着当线程模型不能正常工作时。)

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

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

Apache Mina有一个使用NIO的例子

答案 1 :(得分:2)

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

答案 2 :(得分: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);
        }
    }
}