smux
smux copied to clipboard
一个stream不读数据,另一端stream一直写,直到缓冲满。这个时候绑定在conn上的Session将不能执行任何指令。
// recvLoop keeps on reading from underlying connection if tokens are available
recvLoop()
for {
for atomic.LoadInt32(&s.bucket) <= 0 && !s.IsClosed() {
select {
case <-s.bucketNotify:
case <-s.die:
return
}
}
由这段代码可知,当s.bucket小于0时,将不能从tcp缓冲拿数据。 session 将不能响应 对端的任何指令。包括关闭那个已经写超时的stream。 除非从stream中读数据,腾出缓冲空间
如果设计将指令(cmdSYN,cmdFIN,cmdNOP)与数据接收指令(cmdPSH) 分开接收,可解决关闭那个已经写超时的stream,并回收缓存空间。
但是, 经测试,如果 s.bucket 满后,不再从tcp 中读数据,又会导致tcp的缓冲区满。要拿到关闭指令任然需要将之前的数据取出。
一个待商榷的方案,用两层buffer。
-
session
上一个小buffer(1024),用于tcp
拆粘包。将接收到的完成数据包分到对应的stream
。 -
stream
上一个大buffer(65535),缓冲数据流。
write:从stream
的写wbuffer
中取最多 1024个字节。经session
编码发送到对端,对端 接收到完整包后将其投递到对应stream。若对端 stream buffer不够,响应buffer满,本端尝试重发。
read:直接从 stream 上读取数据。
什么时候尝试重发?假设在stream上设置一个标记,对端write步骤触发本端buffer满时,本端设置标记。本端read步骤时,通告对端可以继续发送了。
上面的 buffer 大小应可以自己调节,避免多次拆包。
lgtm, 为了整体的 SLO,并且保证其它 stream 的最佳性能,应该直接放弃慢的 stream frame,并 RST 对应 Stream。