TCP是否保证按顺序到达?

50

如果我发送了两个TCP消息,我需要处理后一个到达先一个的情况吗?还是它保证按照我发送的顺序到达?我认为这不是Twisted特定的例子,因为它应该符合TCP标准,但如果任何熟悉Twisted的人可以为我的安心提供一个Twisted特定的答案,那将不胜感激 :-)


3
因为TCP不知道你的消息从哪里开始或结束,所以即使它想重新排序它们,它也无法做到。 - David Schwartz
4个回答

56
只要两条消息是在同一TCP连接上发送的,顺序就会保持不变。如果在同一对进程之间打开了多个连接,则可能会出现问题。
关于Twisted或任何其他异步事件系统:我预计您会按照接收字节的顺序收到dataReceived消息。但是,如果你开始将工作推迟到延迟调用中,你可以扭曲你的控制流。

25

TCP是面向连接的协议,可以为其客户端提供有序传输。当然,这仅适用于连接级别:各个连接是独立的。

需要注意的是,通常我们会使用“TCP流”和“UDP消息”这样的术语。

无论您使用哪种客户端库(例如Twisted),底层TCP连接都是独立的。TCP将按顺序向客户端传递“协议消息”。在此,“协议消息”指的当然是您在TCP层上使用的协议。

需要进一步注意的是,I/O操作是异步的,并非确定性的,非常依赖于系统负载,同时也会受到网络延迟和丢包的影响,因此不能保证TCP连接之间的消息顺序。


1
between TCP connections” 是什么意思? - simplename

22
TCP“保证”接收方将接收到发送方最初发送的字节流。然而,在TCP发送/接收端点(即物理网络)之间,数据可能会乱序接收、分段接收、损坏甚至丢失。TCP使用握手机制解决这些问题,导致坏包被重新传输。接收器上的TCP堆栈按照它们被传输的顺序放置这些数据包,因此当您从TCP套接字读取时,您将接收到最初发送的数据。
当您在Twisted中调用doRead方法时,数据将从套接字中读取到缓冲区的大小。这个数据可能代表单个消息、部分消息或多个消息。你需要从缓冲区中提取出消息,但是可以保证这些字节此时处于它们传输的顺序。
很抱歉我之前的帖子搞得有点混乱...

1
请重新审视您的答案,因为它是非常错误的。TCP公开的API实际上是一个具有按字节排序传递的流。您在这里提到的是底层传输方法(即数据包),当然不能保证按顺序到达。 - jldupont
FYI,TCP 的“服务器层”是 IP,它当然是“无连接”的,并且不能保证数据包的顺序传递。 - jldupont
我对你的解释感到困惑 - 在第二句中,你写道数据可能会被损坏(对于TCP客户端?),而在第三句中,你又写道它不会被损坏,因为TCP会处理这种情况。那么TCP客户端能看到什么 - 数据是否已损坏或保证正确?此外,关于数据的顺序,你是指直接连接可以保证顺序,但对于间接连接,TCP客户端可能会看到数据无序吗? - astrowalker

8

TCP是一种流式传输协议,而UDP则是一种消息传输协议。你将这两个术语混淆了。对于TCP来说,流会按照发送顺序到达,并且没有明确的消息边界,字节按照它们到达的顺序出现,将它们解释为消息取决于你。


1
回复:术语 - 当然。不过,Twisted将其抽象为不同的消息(因此将它们解释为消息不是由我决定的)。 - Smashery
值得注意的是,尽管发送方可能有两个写操作,但根据缓冲区大小和网络条件,它们可能会合并为接收方的单个读取操作,反之亦然。 - Andrew Y
1
不,Twisted并没有将TCP抽象为“消息”。在基础协议中,您将获得一块字节(在极端情况下可降至每次一个字节)。 - mthurlin
我认为从应用程序的角度来看是正确的。从协议的角度来看,TCP 本质上是带有许多连接处理、丢失数据包重发、到达顺序等扩展的 UDP。在 Unix API 中很明显:相同的流式 API 调用(write、read)和数据包定向调用(send、recv)都适用于两种类型的套接字。当然,你不能在子数据包级别上操作 UDP "连接",而你可以在字节流级别上读/写 TCP 连接。 - peterh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接