TCP memcpy 缓冲区使用 C++ 返回垃圾数据

Posted

技术标签:

【中文标题】TCP memcpy 缓冲区使用 C++ 返回垃圾数据【英文标题】:TCP memcpy buffer returns rubbish data using C++ 【发布时间】:2011-08-22 05:18:46 【问题描述】:

我正在做类似于 Stack Overflow 问题的事情Handling partial return from recv() TCP in C

接收到的数据大于初始化的缓冲区(例如,1000 字节)。因此使用更大尺寸(例如,10000 字节)的临时缓冲区。问题是收到的多个数据是垃圾。我已经检查了 memcpy 到临时缓冲区的偏移量,但我一直收到垃圾数据。

这个示例展示了我的工作:

收到的第一条消息:

memcpy(tmpBuff, dataRecv, 1000);
offSet = offSet + 1000;

第二个消息开始:

memcpy(tmpBuffer + offSet, dataRecv, 1000);

有什么需要检查的吗?


我检查了发送出去的 TCP 十六进制。显然,发件人正在发送不完整的消息。我的程序的工作原理是,当发件人发送消息时,它会打包(消息头+实际消息)。消息头有一些元数据,其中之一是消息长度。

当接收方接收到数据包时,它会使用消息头偏移量和消息头长度来获取消息头。它将提取消息长度,检查当前数据包大小是否大于或等于消息长度,并将正确的消息大小返回给用户。如果数据包中还有剩余的消息量,它将把它存储到一个临时缓冲区中并等待接收下一个数据包。当它接收到下一个数据包时,它会检查消息头中的消息长度并执行相同的操作。

如果发送方在一个数据包中打包三个消息,则每个消息都有自己的消息头指示消息长度。假设所有三个消息的长度均为 300 字节。还假设发送的第二条消息不完整,结果只有 100 字节。

当接收方收到一个包中的三个消息时,它会正确返回第一个消息。由于第二条消息不完整,我的程序不会知道,因此它将从第二条消息返回 100 字节,从第三条消息返回 200 字节,因为消息头指示总大小为 300 字节。因此,返回的第二条消息将包含一些垃圾数据。

至于第三条消息,我的程序会尝试从消息头中获取消息长度。由于前 200 个字节已返回,因此消息标头无效。因此,返回给我的程序的消息长度也将是垃圾。有没有办法检查完整的消息?

【问题讨论】:

你能显示你的实际代码吗? 是的,展示真实的代码,不是你认为相关的那一小部分,而是全部。 dataRecv 数据正常,tmpBuffer 数据不好? 是的,您应该检查您实际收到的字节数。没有看到代码的最佳猜测是您认为您正在读取 1000 个字节,但实际上获得了 5 个实际字节的数据并移动了 995 个垃圾。 【参考方案1】:

假设您期望 7000 字节通过 tcp 连接。在这种情况下,您的消息很可能会被拆分为实际有效负载大小为 1400 字节(即 5 条消息)的 tcp 数据包。

在这种情况下,目标缓冲区为 1000 字节的连续 recv 调用完全有可能表现如下:

recv -> reads 1000 bytes (packet 1)
recv -> reads 400 bytes (packet 1)
recv -> reads 1000 bytes (packet 2)
recv -> reads 400 bytes (packet 2)
...

现在,在这种情况下,当读取 400 字节数据包时,您仍将完整的 1000 字节复制到更大的缓冲区,实际上在两者之间粘贴了 600 字节的垃圾。您实际上应该只 memcpy 接收到的字节数,这是 recv 本身的返回值。当然你也应该检查这个值是0(socket关闭)还是小于0(socket错误)。

【讨论】:

+1。最常见的套接字编程错误是假设“recv”返回的字节数与您传入的字节数一样多。IP 分段、TCP 分段、tcp 窗口大小和许多其他因素会影响返回的字节数。并且完全独立于相应的发送调用()“发送”了多少字节。 嗨,是的,我知道 KillianDS 提到的内容。事实上,每 1400 个 msg 都会有一个 msg hdr 包含 msg 长度,以便接收端知道 memcpy 的偏移量并返回给用户。有趣的是,如果发送者一次发送 95 条消息,接收者每次都能收到所有的消息。但是如果发件人一次发送100条及以上的消息,可能会出现垃圾数据。我实际上在网络上嗅探十六进制数据并尝试从那里调试

以上是关于TCP memcpy 缓冲区使用 C++ 返回垃圾数据的主要内容,如果未能解决你的问题,请参考以下文章

从 C++ UDP 缓冲区接收字符串

TCP服务器/客户端:客户端recv()返回空白缓冲区

c++中内存拷贝函数(C++ memcpy)详解

缓冲区溢出漏洞实例(打开记事本)

如何提高 memcpy 的性能

memcpy 没有复制到缓冲区