基于 TCP 实现极简的业务流控
我们要实现: TCP 传输通畅的时候,按照预定速率发送; TCP 阻塞 (但是连接没有断开) 时,可以丢掉一些 Message
我想到的一个非常简单的方法是:把 TCP 发送缓冲区调大点,然后调用 send 时,如果能把 Message 一次性填进去,就填进去,否则就把 Message 整个丢掉
问题来了:这个方案可实施吗?如何让 send api 工作在原子的、非阻塞模式?
我们要实现: TCP 传输通畅的时候,按照预定速率发送; TCP 阻塞 (但是连接没有断开) 时,可以丢掉一些 Message
我想到的一个非常简单的方法是:把 TCP 发送缓冲区调大点,然后调用 send 时,如果能把 Message 一次性填进去,就填进去,否则就把 Message 整个丢掉
问题来了:这个方案可实施吗?如何让 send api 工作在原子的、非阻塞模式?
如果消息比较短,UDP 就完全没问题了
这么抽象一下之后,就和使用什么协议没有关系了。
每次生产出一个 Messsage (onNewMessage),就调用一次 queue.push() 方法实现原子操作;另一个线程从 queue 中不断读取数据并发送
在 8F 的解法中:
每次生产一个 Message (onNewMessage),就调用 send() 方法把这个 Message 整个发出去,如果需要等待,就一直阻塞在那里;这时因为发生了阻塞,实际上也就不会有新的 Message 产生
本质上,前者是 “生产不阻塞” 模式,后者是 “阻塞生产” 模式
我想了一下,对我的实际场景,两者都是可以的。但是 8F 的解法对生产的逻辑有一个要求:生产者要能感知到阻塞的发生,在阻塞结束后,测量一下阻塞了多少时间,然后下次生产新的实时数据,而不因为阻塞导致后续生产的数据实时性发生整体偏移
再说了,协议实现怎么知道什么是“message”? TCP 是流式传输,传输层也不可能引入这个概念
没有哪个 socket 实现提供缓冲区的控制,所以你这纯粹是空想
允许丢弃的当然用 UDP,自己切帧再组合就是了,不存在什么“长度不够”
想那么多,难道不会写个 demo 验证自己的想法?如果没有验证的能力,那还是多学习,少思考比较好。
但是如果采用 3F / 8F 的方案,就没有这个问题了
3F / 8F 已经给出比较好的解法了,3F 是一个解法,8F 是一个绕过的思路
https://stackoverflow.com/questions/38359272/linux-sockets-how-to-get-number-of-bytes-packets-in-sending-buffer
所以这就是第三个解法了 🙂