Ktor TCP读取字节
我想请教或确认。若我想在Kotlin Multiplatform(KMP)中通过Ktor从 TCP连接读取原始字节,是不可能的,还是没有原生库函数可以帮助我在一个TCP数据包内读取所有字节。我的意思是,我需要在一个TCP数据包内读取所有字节,其长度有时可能超过50字节,甚至可能达到3000字节或更多。我在这里在寻求一个选项。是否需要创建某种专有包装器,用来分割有效载荷并包含数据载荷的TVL结构,并据此自定义Ktor的读取函数?还是有其他选项?我的意思是,Ktor是否有某个函数可以先缓冲来自一个TCP数据包的所有字节,然后再立即返回这些数据,而无需等待某个结束字符或专有长度字段?此外,如果我通过TCP/IP发送数据包,长度假设超过5000字节,它会按该大小到达吗?因为在某些设备上内部缓冲区大小可能有限吗?另外,我是否需要在该数据包中加入额外的校验,还是可以依赖数据层的包校验?关于时间和延迟,在通过长距离接收数据时,使用TCP,时间可能无法可靠地预测,因此在接收函数中在每个字节后等待固定时间可能并不可靠,对吗?网上有很多来源,但我不确定哪一个是正确的。
解决方案
我是否需要创建一个专有包装器,用来分割载荷并包含数据载荷的TVL结构,并据此定制Ktor的读取函数?
还是有其他选项?我的意思是,Ktor是否有某个函数可以先缓冲来自一个TCP数据包的所有字节,然后再立即返回这些数据,而无需等待结束字符或专有长度字段?
另外,如果我通过TCP/IP发送一个长度超过5000字节的数据包。
它会按这个大小到达吗?因为在某些设备上内部缓冲区大小可能有限吗?
另外,我是否需要在该数据包中增加额外的校验,还是可以依赖数据层的包校验?
关于时间和延迟,在长距离通过TCP接收数据时,时间可能无法可靠地依赖,因此在接收函数中在每个字节后等待固定时间可能并不可靠,对吗?
同样,TCP没有数据包边界,它只是一个连续的字节流。所以在基于TCP的协议中,创建带长度前缀的自定义数据包结构是相当常见的,也许是最可靠的做法。
(例如,TLS使用长度字段。SMTP是基于行的,使用CRLF作为分隔符。HTTP/1.x使用基于行的头部,并为载荷提供Content-Length字段。)再次强调,TCP实际上并没有“包”这一概念。接收方无法可靠地区分一次5000字节写入和多次分写入的边界,因此它不能保证真正“完成”接收。几乎所有协议要么使用长度字段,要么使用定界符。
在互联网上,标准的MTU(最大IP数据包尺寸)是1500,因此如果写入5000字节,它将被分成若干TCP段(若MTU为 1500,典型的最大TCP段约为1440字节),在4–5个独立的IP数据包中传输,接收端会将它们重新组装为连续的字节流。
因此如果接收端请求 "recv(9001)",它确实会收到当前缓冲中的5000字节,但不能保证这是完整的数据。另外,如果我通过TCP/IP发送一个长度超过5000字节的数据包。
会按这个大小到达吗?因为在某些设备上内部缓冲区大小可能有限吗?会的,因为TCP有流量控制——它使用滑动窗口机制,发送方一次只能发送一定数量的字节,接收方在处理收到的数据时会逐步扩大窗口。因此多出的数据不会丢失,而是被发送方缓冲起来。
如果接收端确实无法一次处理超过1k的数据,它会在其“窗口大小”中表现出来。你的5000字节将首先存放在发送端缓冲区中,并在接收端对已处理的数据进行ACK时逐步传输。
如果接收端根本不调用read() 或recv(),同样也会发生——操作系统会缓冲一定量的已接收数据,然后停止扩大窗口,发送方就会明白不允许再发送更多。
到某个时点,发送方的缓冲区会填满,此时后续的同步send() 调用将阻塞(暂停整个线程),因此多出的数据也不会丢失。另外,我是否需要在该数据包中增加额外的校验,还是可以依赖数据层的包校验?
就数据损坏而言,你基本可以依赖底层的可靠性。许多应用层协议本身并不包含自带的错误检查。
不过,现在应使用TLS——TLS自身具备验证能力,因为用来防止对数据包篡改的MAC,同样也能检测到其它的损坏(万一在TCP及以下层的校验和中未能通过检查时)。关于时间和延迟,在长距离通过TCP接收数据时,时间可能无法可靠地依赖,因此在接收函数中在每个字节后等待固定时间可能并不可靠,对吗?
没必要。TCP已经为你处理了流量控制和拥塞控制,操作系统也会对接收到的数据进行缓冲。