Java - 服务器网络特定客户端聊天

Java - server networking specific client chat

我创建了一个简单的聊天服务器,可以写入所有连接的客户端(为简单起见,我只发布了核心代码)

public class server extends Thread {

private Socket clientSocket;
private static ArrayList<Socket> sockets = new ArrayList<Socket>();

public server(Socket clientSocket) {
    this.clientSocket = clientSocket;
    sockets.add(clientSocket);
}

public void run() {
    while (true) {
        try {
            for(Socket s: sockets) {
            //write something
            //the for loop will send it to every socket in the array
            }
        } catch (Exception e) {
            //catch it
        }   
    }    
}
}   

现在我想更具体地说明我想将消息发送到哪个客户端,就像真实世界的聊天应用程序会有不同的聊天室一样。

所以如果Client1连接到服务器,他会想要创建一个名为 "Apple"。然后当Client2和Client3连接时,他们可以选择加入群组"Apple"。同时,客户端 4 将连接到服务器并创建另一个名为 "Banana" 的聊天组,其他客户端可以加入并在那里聊天。

我的理解是我需要以某种方式识别服务器接受的每个客户端(我不知道如何实现)。然后我是否根据他们的群聊名称以某种方式将它们全部放入自己的数组中?

我一直在寻找过去一周的示例代码,这些代码允许同时进行 1 个以上的群聊,但我看到的所有内容都只适合 1 个。

最简单的解决方案是使用 hashmap,键 = 房间名称,值 = 聊天中的用户列表。在实践中:

HashMap<String, ArrayList<Socket>> rooms = new HashMap<>();

当一个新用户连接时,它应该发送一条消息,其中包含他想要连接的房间的名称,然后您可以检查房间是否已经存在:

ArrayList<Socket> clientsList = rooms.get(roomName);
if(clientsList == null) {
    clientsList = new ArrayList<Socket>();
    rooms.put(roomName, clientsList);
}
clientsList.add(socket);

另一个好主意是创建一个包含套接字和其他信息(例如用户名)的客户端 class。

关于性能方面我建议你看看Java nio, nio2。使用 nio,您可以以异步方式处理连接,并且不会在每个连接上浪费 1 个线程。标准套接字实现有一些缺点。

为了解决您的问题,我希望将 header 和消息内容 sent/received 分开。 header中会有源用户、目标user/group等信息。 您的客户将理解消息并将消息打印到与正确发件人相关的聊天 windows 中。

在服务器端,你可能有 用户映射,键为 userName,值为 User Object。 ChatGroups 映射,键是组名,值是用户名列表。 由于关系是多对多的,因此您还需要保留用户的所有参与组。将 groupNameList 放入 User Object 或定义一个单独的映射。

监听客户端套接字 onClose 操作(可能与 nio 一起使用)并使用阻塞机制(并发)从组或映射中删除用户

添加新组、用户等也需要线程并发。