我目前正在用 C# 编写一个自下而上的聊天服务器。
就像一个单独的大房间,所有客户都在里面,然后你也可以发起私人聊天。我还为将来集成多个房间(但现在没有必要)制定了代码。
写它主要是为了好玩,但也因为我要为像我这样的年轻人创建一个新的聊天网站,因为丹麦已经没有人了。
我刚刚用 170 个客户端测试了它(用 Javascript 编写,带有 JQuery 和 Flash 桥接套接字连接)。本地网络上从消息发送到传递的响应时间不到 1 秒。但现在我正在考虑我能够从中挤出什么样的表现。
我可以看到我是否连接了两个客户端,然后连接了 168 个其他客户端,并在客户端 2 上写入并观察客户端 1,它立即出现在客户端 1 上。CPU 使用率和 RAM 使用率根本没有显示服务器压力的迹象。它处理得很好,我认为它可以扩展到至少 1000 - 1500 没有丝毫问题。
然而,我注意到了一些事情,那就是如果我再次打开 170 个客户端并在客户端 1 上发送一条消息并在客户端 170 上观看,则会有大约 750 毫秒左右的日志。我知道问题所在,也就是说,当服务器接收到聊天消息时,它会将其广播给服务器上的每个客户端。然而,它确实需要枚举所有这些客户端,这需要时间。现在的延迟对于聊天来说是可以接受的,但我担心客户端 1 发送到客户端 750 可能(尚未测试)需要 2 - 3 秒。当我开始每秒收到 2 到 3 条消息时,我也很担心。
所以总结一下,我想加快服务器广播过程。我已经在使用并行 foreach 循环,并且还在使用异步套接字。
这是广播代码:
lock (_clientLock)
{
Parallel.ForEach(_clients, c =>
{
c.Value.Send(message);
});
}
这是在每个客户端上调用的发送函数:
try {
byte[] bytesOut = System.Text.Encoding.UTF8.GetBytes(message + "\0");
_socket.BeginSend(bytesOut, 0, bytesOut.Length, SocketFlags.None, new AsyncCallback(OnSocketSent), null);
}
catch (Exception ex) { Drop(); }
我想知道是否有任何方法可以加快速度?我考虑过编写某种辅助类来接受队列中的消息,然后使用大约 20 个线程来拆分广播列表。
但我想知道你对这个话题的看法,我是学生,我想学习!(:
顺便提一句。我喜欢你在发布到堆栈溢出时如何发现代码中的问题。我现在制作了一个重载函数,以便在使用广播时接受来自服务器类的字节数组,因此 UTF-8 转换只需要发生一次。同样为了安全起见,字节数组长度的计算现在只发生一次。请参阅下面的更新版本。但我仍然对改进这一点的方法感兴趣!
更新广播功能:
lock (_clientLock)
{
byte[] bytesOut = System.Text.Encoding.UTF8.GetBytes(message + "\0");
int bytesOutLength = bytesOut.Length;
Parallel.ForEach(_clients, c =>
{
c.Value.Send(bytesOut, bytesOutLength);
});
}
更新了客户端对象的发送功能:
public void Send(byte[] message, int length)
{
try
{
_socket.BeginSend(message, 0, length, SocketFlags.None, new AsyncCallback(OnSocketSent), null);
}
catch (Exception ex) { Drop(); }
}