我有一个生成数据的服务器,客户端接收这些数据。只有服务器速度太快,使客户端过载。最终,服务器将阻止他的发送操作。
现在,我对来自服务器的旧数据并不真正感兴趣,相反,服务器可以跳过一些消息,只发送对客户端真正重要的东西。
在客户端上,我可以使用Client.Available
来找出流中还剩多少数据,但我无法弄清楚如何在服务器/发送者上获取此数字。我可以更改SendBufferSize
,但相反,我会知道 SendBuffer 中有多少可用空间并相应地做出反应。
我可以让客户报告他落后了多远,但这感觉就像在应用程序级别重新发明TCP协议。另外,我不相信已经很慢的客户端会及时警告我的服务器。
有没有办法读取TCP使用/未使用的窗口大小或发送缓冲区?
"最终,服务器将阻止他的发送操作"
坦率地说,以上是这里真正的错误。服务器没有理由仅仅因为某些客户端接收数据的速度不够快而阻止。服务器应使用非阻塞的异步 I/O,否则应继续正常工作,即使客户端的读取速度不够快。
现在,即使您解决了阻塞问题,您也可能遇到客户端接收数据速度不够快的问题。即,正如您提到的,您希望客户端不接收它无法处理的数据。您在这里至少有几个选择:
- 要求客户端在发送另一条消息之前主动响应已处理的消息。
优点:这是一个即时的解决方案,从某种意义上说,服务器永远不会超过客户端可以处理的传输速率.
缺点:这会增加网络协议的带宽开销和延迟。具有高 ping 时间的客户端将受到影响,即使它能够以其他方式快速接收数据。
- 跟踪客户端似乎能够处理的数据速率,并减慢消息的具体化速度,以便服务器不超过此速率。
优点:此解决方案将始终保持客户端能够处理的传输速率
缺点:至少在最初,也许是间歇性的,因为客户自身的能力会有所不同,这可能会暂时超过客户跟上的能力
- 使用 UDP,这将允许网络传输层丢弃客户端处理速度不够快的数据报。
优点:此解决方案将整个问题委托给网络传输层,让您担心服务器和客户端的真实细节
缺点:UDP 本质上是不可靠的。除了处理丢弃的数据报(在您的情况下这是一个好处)之外,您还必须准备好处理无序接收的数据报,以及多次接收的单个数据报。
考虑到广泛陈述的问题,这是一个尽可能具体的答案。
将TcpClient.SendTimeout
设置为合理的值。如果客户端在超时到期之前不接受和使用消息,则 Write
方法(及其重载)将引发SocketException
。您应该编写一个 catch-block,然后决定是重试操作还是丢弃消息。