【问题标题】:Why am I losing this byte in the send() function?为什么我在 send() 函数中丢失了这个字节?
【发布时间】:2023-10-23 14:01:01
【问题描述】:

我们的应用程序是一个与 Windows Java 客户端通信的 C 服务器(这个问题是针对所述服务器的 Windows 端口的)。在这个特定的例子中,我们正在向客户端发送数据,特别是,消息由一个 7 字节的标头组成,其中前 3 个字节都有特定的含义(操作类型、标志等),最后 4 个字节包含消息的其余部分。出于某种原因,我完全无法弄清楚,标题中的第三个字节以某种方式发生了变化;如果我在send() 上设置一个断点,我可以看到第三个字节是我所期望的(0xfe),但是当我签入客户端时,该字节设置为 0。每隔一个字节就可以了. A 使用 WireShark 进行了一些流量捕获,发现离开服务器的字节为 0,我觉得这更令人费解。第三个字节是通过定义设置的,ala:

#define GET_TOP_FRAME   0xfe

我做的一些测试进一步混淆了这个问题:

  1. 我将值从使用定义更改为第一个0x640xff0xfd:全部都交给了客户。
  2. 我将值从使用定义更改为使用0xfe 本身:客户端的值为零。
  3. 我将定义本身的值从 0xfe 更改为 0xef:客户端的值为零。

这没有什么意义。代码经历了几个层次的功能,但这里是大部分核心代码:

int nbytes; /* network order bytes */
static int sendsize = 7;
unsigned char tbuffer[7];
tbuffer[0]= protocolByte;
tbuffer[1]= op;
tbuffer[2]= GET_TOP_FRAME;
nbytes = htonl(bytes);
memcpy((tbuffer+3), &nbytes, JAVA_INT);

send(fd, tbuffer, sendsize, 0);

其中fd 是先前组合的套接字,protocolByteopbytes 是先前设置的。然后,它会在此消息之后立即使用非常相似的发送命令发送消息的其余部分。正如我所提到的,如果我在该发送函数上设置一个断点,则 tbuffer 包含的正是我所期望的。

这里有人有什么想法吗?我完全被难住了;这对我来说毫无意义。谢谢。

【问题讨论】:

  • 完整的 7 字节数据包在网络上传输? (根据wireshark?)
  • 是的。根据 Wireshark 的说法,除了那个神秘变化的单字节之外,我期望的一切都在那里。
  • 您是否尝试禁用编译器优化?
  • 看起来在我的调试版本中它从未启用过。

标签: c sockets winsock


【解决方案1】:

可能是您的系统某处存在一个简单的错误,导致简单的缓冲区溢出或类似情况,但鉴于这些信息很少,很难判断出在哪里。但是,请记住:

TCP 不发送消息——它是一个流。一个 send() 调用可能需要几个 recv() 调用才能接收。一个 recv 调用可能会收到您的应用程序定义的部分“消息”。

你在检查 send 的返回值吗?和 recv 的返回值? send 发送的字节数可能比您告诉它的少。如果你给它一个足够大的缓冲区,recv 接收的字节可能比你告诉它的少,或者它接收的数据可能比你的应用程序“消息”之一多。

【讨论】:

  • 好点。我们实际上是在一个循环中调用send(),检查发送的字节,这样我们就可以保证我们正在发送所有内容。客户端的接收代码被抽象了一点,所以它的作用并不明显,而且一旦我确定由于 Wireshark 数据而问题必须出在服务器上,我就不再仔细研究它了。
【解决方案2】:

原来还有别的东西阻碍了我们:除了 C 服务器之外,我们还有一个 Tomcat/Java 服务器,它运行在一切之上;老实说,我没有参与那部分开发,所以我不太了解它。事实证明,我们有一些代码在中间层部分和我们的客户端之间共享;此共享代码在离开服务器时占用该特定字节,如果将其设置为 0xfe,则将其设置为未初始化的值(因此为零)。然后,当它到达客户时,它是错误的。这就是为什么当我在 C 代码中将值设置为不同的东西时,它会出现在另一端,以及行为似乎不一致的原因;我在 Java 中切换了很多值以查看发生了什么。

感谢大家的指点,但事实证明这只是我没有正确理解路径的情况。

【讨论】:

    最近更新 更多