xtaci / smux

A Stream Multiplexing Library for golang with least memory usage(TDMA)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

一个stream不读数据,另一端stream一直写,直到缓冲满。这个时候绑定在conn上的Session将不能执行任何指令。

yddeng opened this issue · comments

commented
commented
// 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中读数据,腾出缓冲空间

commented

如果设计将指令(cmdSYN,cmdFIN,cmdNOP)与数据接收指令(cmdPSH) 分开接收,可解决关闭那个已经写超时的stream,并回收缓存空间。

但是,
经测试,如果 s.bucket 满后,不再从tcp 中读数据,又会导致tcp的缓冲区满。要拿到关闭指令任然需要将之前的数据取出。

commented

一个待商榷的方案,用两层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。