“广播”到 TCP 客户端列表的最快方法
Posted
技术标签:
【中文标题】“广播”到 TCP 客户端列表的最快方法【英文标题】:Fastest way to "broadcast" to list of TCP clients 【发布时间】:2012-07-21 22:17:03 【问题描述】:我目前正在用 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();
【问题讨论】:
+1 好且简洁的问题。 【参考方案1】:~1s 对于本地网络来说听起来真的很慢。平均 LAN 延迟为 0.3 毫秒。 Nagle 是启用还是禁用?我猜它已启用......所以:改变它(Socket.NoDelay
)。当然,确实意味着您必须负责不以过度碎片化的方式写入套接字 - 所以不要逐个字符地滴漏消息。在内存中组装要发送的消息(或者更好的是:多个未完成的消息),并将其作为一个单元发送。
【讨论】:
Nagle 算法现在被 Socket.NoDelay() 禁用。我不知道它是否有很大帮助,也许有点。我仍然怀疑客户的枚举是一个问题。消息已立即发送。它们是 JSON 编码的字符串,当我调用广播时,它总是一条完整的消息(因此附加了一个 0 字节作为消息分隔符)。无论如何,无论是什么原因,我都在寻求加快速度的技巧,也是为了学习。并发和性能都是很棒的话题! 嗯,我开始认为这也是关于在同一台 PC 上运行的多个浏览器都执行 Javascript。我开始深入研究代码,我的服务器显示 2 毫秒来枚举客户端和广播消息。我将开始进一步调查。以上是关于“广播”到 TCP 客户端列表的最快方法的主要内容,如果未能解决你的问题,请参考以下文章