【问题标题】:Socket not receiving the complete stream套接字未接收到完整的流
【发布时间】:2014-09-08 02:14:18
【问题描述】:

我正在编写一个程序来发送和另一个程序通过套接字接收图像流。笼统地说:

  • 在客户端:我获取图像并在客户端对其进行预可视化。然后我通过套接字发送它。

  • 在服务器端:我等待图像,然后对其进行预可视化。

这里是socket相关的sn-ps代码:

已编辑:

客户端

unsigned int bytes = 0;
for (int i = 0; i < imgSize; i += bytes) {
    if ((bytes = send(clientSocket->getSocketDescriptor(), (char*)inputImage.data + i, imgSize - i, 0)) == 0) {
        assert(false);
    }
    std::cout << "Sent: " << bytes << std::endl;
}
char notifyChar[1];
recv(clientSocket->getSocketDescriptor(), notifyChar , 1 , 0);

服务器端

unsigned int bytes = 0;
for (int i = 0; i < imgSize; i += bytes) {
    if ((bytes = recv(serverQuads.getSocketDescriptor(0), (char *)sockData + i, imgSize - i, 0)) == -1) {
        assert(false);
    }
    std::cout << " Received: " << bytes << std::endl;
}       

char notifyChar[1] = { '0' };
send(serverQuads.getSocketDescriptor(0),notifyChar , 1, 0);

图像大小为 57600(imgSize 由 3 个 const(WIDTHHEIGHTCHANNELS)计算得出,send() 返回该值。但是服务器只接收到 53504 字节,所以它返回到recv() 但没有任何反应。它一直在无休止地等待其他 4096 字节。

我现在有点困惑。我阅读了很多帖子,但找不到问题所在。有人可以帮帮我吗?

已解决:

错误出在这个 sn-ps 之外。另一个线程正在从 socketDescriptor 读取并等待正好 4096 个字节。所以,现在一切都很好。

【问题讨论】:

  • 首先你要记住TCP是一个streaming协议,它并没有真正的“数据包”,它只是一个数据流,也就是说如果您发送两个“数据包”,它们可能会在另一端作为一个接收。另外,您确定两端的数据包大小相等吗?在两端打印出PACKET_SIZE
  • 您使用的是 TCP 还是 UDP 哪个协议?为什么不使用库来处理这样的事情呢?
  • TCP 还是 UDP?为什么即使bytes != 2400 仍打印“已接收:2400 字节”?
  • 另请注意,除非图像大小是PACKET_SIZE 的倍数,否则您不会发送完整的图像。
  • recv 只得到部分缓冲区是正常的。一定要注意recv返回的值,一直调用recv,直到有完整的画面。您可能还会得到一张完整的图片以及下一张的一部分。您的代码负责将部分正确地重新组合在一起。

标签: c++ sockets


【解决方案1】:

您没有使用recv 的返回值来确定接收了多少字节。 TCP 为您提供无边界的数据流。它不是基于消息的。

这意味着您可以在一次阅读呼叫中接收部分消息或多条消息。您的代码必须能够处理这个问题。

【讨论】:

  • 现在我使用recv的返回值,但接收的字节数比发送的少。
  • 您正在使用未初始化的变量字节。这是未定义的行为。修复它。
  • 我刚刚修复它,但问题是一样的。幸运的是bytes在赋值之前没有被使用。
  • 代码看起来不错。其他事情正在发生。也许,您在尝试读取图像之前已经从同一个套接字读取了 4096 个字节。您可能不小心丢弃了数据。 4096 是一个可疑值。听起来像你的缓冲区大小。
  • 是的,这个尺寸非常可疑......我认为它以前从未使用过,但我会调查它。一旦我得到一些结果,我会评论你。谢谢你
【解决方案2】:

在 windows 和 linux 上 recv() 的第三个参数是 char[] 缓冲区的大小,而不是接收到的大小。它用于防止分段错误错误。

【讨论】:

  • 我认为现在用新的sn-p代码解决了。但接收的字节数比发送的少
【解决方案3】:

我会建议你以下

  • 当您从客户端发送数据包时,在各个数据包传输之间引入几秒钟的延迟(这仅用于调试)。然后检查服务器端是否接收到单个数据包。 如果启用了 tcpdump,则在客户端上运行以下命令:

    tcpdump -nnv -s0 -ieth0 dst 主机 dsthostip 和 tcp

以及服务器上的以下命令

tcpdump -nnv -s0 -ieth0 src host srchostip and tcp

检查这些命令的输出,以确保正在传输和接收正确大小的数据包,如果不是,那么哪一方是罪魁祸首。

  • 检查套接字缓冲区的大小。套接字缓冲区有一个默认大小(我相信 64KB 是默认值),如果数据到达太快,套接字缓冲区可能会溢出并且数据包可能会丢失,尽管如果使用 TCP 套接字,这应该是不太可能发生的情况。您可以增加缓冲区的大小并检查问题是否仍然存在。

  • 在服务器端运行 netstat -s 命令并检查 IP 和 TCP 标签下是否有任何数据包丢失或丢弃。 希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-18
    • 2020-07-23
    • 1970-01-01
    相关资源
    最近更新 更多