【问题标题】:Receiving data in TCP在 TCP 中接收数据
【发布时间】:2010-12-10 00:58:33
【问题描述】:

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

编辑:问题来自应用程序的角度。如果这 1000 个字节在到达应用程序之前被重新组装成一个缓冲区..那么我不在乎它是否在路上被碎片化了..

【问题讨论】:

    标签: c# c++ networking tcp


    【解决方案1】:

    Transmission Control Protocol:

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

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

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

    【讨论】:

    • 或者你可以像 SMTP 那样做,包括一个终止符字符串(. 在它自己的行上)
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        您在您的消息中决定您的消息应包含多少字节。例如,在您的情况下,它是 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:祝您好运。

        【讨论】:

          【解决方案5】:

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

          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
             }
          }
          

          【讨论】:

            【解决方案6】:

            TCP 保证它们将接收所有 1000 个字节,但不一定按顺序接收(尽管它对接收应用程序来说是这样的),也不一定一次全部接收(除非您自己制作数据包并使其如此。)。

            也就是说,对于一个小至 1000 字节的数据包,它很有可能会发送一个数据包,只要您在一次调用 send 时发送它,但对于较大的传输它可能不会。

            【讨论】:

            • @Matthew Scharley,从 TCP 客户端的角度来看,TCP 确实保证它按顺序传递数据报。底层 IP 不会,因此它可能会重新排序它们,但这是 TCP 的内部细节。
            • 数据包也是如此。但是OP很担心他们。你是对的,我暗示接收应用程序将始终按顺序接收它们。但它们不一定按顺序传送到计算机。
            【解决方案7】:

            TCP 层唯一保证的是接收方会收到:

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

            对于如何将字节拆分为“​​数据包”,根本无法保证。你可能读到的所有关于 MTU、数据包分段、最大段大小或其他任何东西的东西都在 TCP 套接字层之下,并且是无关紧要的。 TCP只提供流服务

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

            【讨论】:

              【解决方案8】:

              传输控制协议要求接收方确认每个数据包已成功交付给发送方,从而保证所有数据包的成功交付。根据这个定义,当有效负载的大小超过MTU (maximum transmission unit) 时,接收方将始终以块的形式接收有效负载。

              更多信息请阅读Transmission Control Protocol

              【讨论】:

              • “数据包大小”是指例如 IPv4 对 65,507 字节的限制?
              • 对不起,我的意思是 MTU - 我已经编辑了我的答案以反映这一点。
              • TCP 保证成功传输数据,但不保证数据包 - 请参阅我关于重新传输的回复。
              【解决方案9】:

              IP 数据包在重传过程中可能会出现碎片。

              因此目标机器可能会接收到多个数据包——这些数据包将由 TCP/IP 堆栈重新组合回来。根据您使用的网络 API - 数据将被提供给 重新组合或以原始数据包的形式。

              【讨论】:

                【解决方案10】:

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

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-09-13
                  • 1970-01-01
                  • 2018-09-17
                  相关资源
                  最近更新 更多