在TCP中接收数据

如果我在TCP中发送1000个字节,它是否保证接收器将获得整个1000字节“togther”? 或者他可能会先获得500个字节,之后他会收到其他字节?

编辑 :问题来自应用程序的观点。 如果1000个字节在到达应用程序之前重新组装到单个缓冲区中..那么我不在乎它是否在路上被分段。

请参阅传输控制协议 :

TCP提供从一台计算机上的程序到另一台计算机上另一程序的可靠,有序的字节流传送。

“流”意味着从接收者的角度来看没有消息边界。 您可以获得一条1000字节的消息或一千条1字节的消息,具体取决于下面的内容以及调用read / select的频率。

编辑 :让我从应用程序的角度澄清。 不,TCP不保证单次读取会为您提供发送方可能发送的所有1000字节(或1MB或1GB)数据包。 因此,TCP上方的协议通常包含固定长度的头部,其中包含总内容长度。 例如,您总是可以发送1个字节来指示内容的总长度(以字节为单位),最多可支持255个字节。

正如其他答案所示,TCP是一种协议 – 每个发送的字节都将被接收(一次并以相同的顺序),但没有内在的“消息边界” – 是否所有字节都是在单个.send调用中发送的,或者多个,它们仍然可以在一个或多个.receive呼叫中接收。

因此,如果您需要“消息边界”,则需要将它们强加于TCP流IOW,基本上是应用程序级别。 例如,如果您知道您发送的字节将永远不会包含\0 ,则以null结尾的字符串可以正常工作; 各种“转义”方法让你发送不遵守这些限制的字节串。 (现有协议,但没有一个真正普遍或广泛接受)。

基本上就TCP来说,它只保证从一端发送到另一端的数据将以相同的顺序发送。 现在通常你要做的就是有一个内部缓冲区,它一直循环,直到它收到你的1000字节“数据包”。 因为上面提到的recv命令返回实际收到的数量。 因此,通常您必须在TCP之上实现协议,以确保以适当的速度发送数据。 因为如果你发送()一次运行中的所有数据,它将使位于下面的网络堆栈重载,这将导致复杂化。 因此,通常在协议中会发送一个微小的确认数据包,以确认发送了1000个字节的数据包。

您在消息中决定消息应包含多少字节。 例如在你的情况下它是1000.以下是启动并运行C#代码来实现相同的目标。 该方法返回1000个字节。 中止代码是0字节; 你可以根据自己的需要定制。

用法:

 strMsg = ReadData(thisTcpClient.Client, 1000, out bDisconnected); 

以下是方法:

  string ReadData(Socket sckClient, int nBytesToRead, out bool bShouldDisconnect) { bShouldDisconnect = false; byte[] byteBuffer = new byte[nBytesToRead]; Array.Clear(byteBuffer, 0, byteBuffer.Length); int nDataRead = 0; int nStartIndex = 0; while (nDataRead < nBytesToRead) { int nBytesRead = sckClient.Receive(byteBuffer, nStartIndex, nBytesToRead - nStartIndex, SocketFlags.None); if (0 == nBytesRead) { bShouldDisconnect = true; //0 bytes received; assuming disconnect signal break; } nDataRead += nBytesRead; nStartIndex += nBytesRead; } return Encoding.Default.GetString(byteBuffer, 0, nDataRead); } 

让我们知道这对你没有帮助(0:祝你好运。

是的,有机会逐个接收数据包。 希望这篇msdn文章和以下示例(摘自msdn中的文章以便快速查看)对您有所帮助,如果您使用的是Windows套接字。

 void CChatSocket::OnReceive(int nErrorCode) { CSocket::OnReceive(nErrorCode); DWORD dwReceived; if (IOCtl(FIONREAD, &dwReceived)) { if (dwReceived >= dwExpected) // Process only if you have enough data m_pDoc->ProcessPendingRead(); } else { // Error handling here } } 

TCP保证它们将接收所有1000个字节,但不一定按顺序(但是,它将对接收应用程序显示)并且不一定全部(除非您自己制作数据包并使之成为。)。

也就是说,对于一个小到1000字节的数据包,只要你在一次调用发送中就可以发送一个数据包,但是对于较大的传输它可能没有。

TCP层唯一保证的是接收器将接收:

  • 发送方传输的所有字节
  • 以相同的顺序

完全没有关于如何将字节分成“数据包”的保证。 您可能阅读的有关MTU,数据包碎片,最大段大小或其他任何内容的所有内容都在TCP套接字层之下,并且无关紧要。 TCP 提供流服务。

参考您的问题,这意味着接收器可能会收到前500个字节,然后接收下500个字节。 或者,接收器可能一次接收一个字节的数据,如果这是它要求的。 这就是recv()函数接受一个参数来告诉它要返回多少数据的原因,而不是它告诉你数据包有多大

传输控制协议通过要求接收方确认每个分组成功传送给发送方来保证所有分组的成功传送。 通过该定义,当有效载荷的大小超过MTU(最大传输单元)时,接收器将总是以块的forms接收有效载荷。

有关更多信息,请阅读传输控制协议 。

在重传期间,IP分组可能被分段。

因此,目标机器可能会收到多个数据包 – 这些数据包将由TCP / IP堆栈重新组装。 根据您使用的网络API,数据将重新组装或以RAW数据包的forms提供给

它取决于稳定的MTU(最大传输单位)。 如果您的建立连接(一旦握手)指的是512字节的MTU,您将需要两个或更多TCP数据包来发送1000个字节。