同一 TCP 连接中的两个 sendall 之间是否完全隔离?

Is there complete isolation between two sendalls in the same TCP connection?

这个TCP问题困扰我很久了,但是由于在本地实验环境下模拟丢包比较困难(本地网速很快,丢包比较困难),所以我有找不到答案。

我的问题是我想在基于TCP协议的两个进程之间实现一个RPC。最高效的方法是建立一次连接,然后这个连接就可以反复使用,这样我就不用重复三次握手和四次分手的过程了。但是在我实现的过程中,服务端收到的包经常是多个请求混在一起,没有隔离,导致我的设计出现问题。

众所周知,建立连接后,如果我的客户端调用socket.sendall(A),其中我们假设A是一个40KB长的包,里面包含了请求的详细信息。由于包内容太长,假设内核自动将这个包拆分成10个包,分10次发送出去。我们都知道,由于 TCP 连接的可靠行为,如果在传输过程中十个包中的第九个碰巧丢失(并且假设客户端程序恰好在所有包发送完后就死了,那么重新发送就不会发生) possible), 那么服务器端的应用层只会读取前八个包的内容,而第十个包即使被正确读取也不会得到。

我的问题是,如果客户端依次发送两个请求

import socket

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((HOST, PORT))
client.sendall(A)
client.sendall(B)
client.close()

并假设请求 A 的第 9 个包在传输过程中丢失,所有其他包都已正确接收。我们服务端使用socket.recv(4)先读取包1,得知接下来的40KB内容属于请求A,但是请求A的可靠包只有8个,在这种特殊情况下,如果服务端应用层继续调用 socket.recv(),它会混合读取请求 B 的内容吗?

如果我想保证两个RPC请求互不干扰,是否必须为每个请求建立不同的TCP连接,而不是在同一个连接中多次传递请求内容?

谢谢!

TCP 保证数据按顺序没有任何间隙传送,即如果数据包丢失,丢失后的数据只会一旦丢失的数据被恢复(即重新提交和接收)并交付给应用程序,就会交付给应用程序。

虽然 TCP 是一个字节流。两个连续 sendsendall 之间的“边界”不是此字节流的一部分,只是有效负载本身。这意味着 sendsendall 可能不完全匹配另一侧的 recv - 这是一个经常但错误的假设。如果需要某种消息语义(例如“请求”、“响应”之类的东西),此 消息语义需要明确成为数据的一部分 并且不能从希望中导出单个 recv 将始终匹配单个 send。实现此目的的典型方法是为消息添加长度前缀或使用特殊字节序列作为消息分隔符。