【问题标题】:Recv function for TCP Socket programmingTCP Socket编程的recv函数
【发布时间】:2018-12-18 01:04:29
【问题描述】:

我是套接字编程的新手。我正在尝试创建一个客户端应用程序。服务器是使用 TCP 通信的摄像机。相机正在发送连续数据。使用 Wireshark,我可以看到相机正在发送不同大小的连续数据包,但不超过 1514 字节。但是我的recv 函数总是返回2000,这是我缓冲区的大小。

unsigned char buf[2000];
int bytesIn = recv(sock, (char*)buf, sizeof(buf) , 0);
if (bytesIn > 0)
{
    std::cout << bytesIn << std::endl;
}

我收到的第一个数据包大小为 9 字节,recv 返回正确,但之后总是返回 2000。

谁能告诉我解决方案,以便我可以得到实际数据负载的正确大小?

编辑

int bytesIn = recv(sock, (char*)buf, sizeof(buf) , 0);
if (bytesIn > 0)
{
    while (bytes != 1514)
    {
        if (count == 221184)
        {
            break;
        }
        buffer[count++] = buf[bytes++];
    }
    std::cout << count;
}

编辑

这是我的 Wireshark 捕获:

处理数据包的代码

int bytesIn = recv(sock, (char*)&buf, sizeof(buf) , 0);
        if (bytesIn > 0)
        {
            if (flag1 == true)
            {
                while ((bytes != 1460 && (buf[bytes] != 0)) && _fillFlag)
                {
                    buffer[fill++] = buf[bytes++];

                    if (fill == 221184)
                    {
                        flag1 = false;
                        _fillFlag = false;
                        fill = 0;
                        queue.Enqueue(buffer, sizeof(buffer));
                        break;
                    }
                }
            }
            if ((strncmp(buf, _string2, 10) == 0))
            {
                flag1 = true;
            }
        }

对于每帧相机发送 221184 字节,在每帧之后它发送一个数据包 9 个字节,我用来比较这 9 个字节是恒定的。

相机发送的这个 221184 字节没有 0,所以我在 while 循环中使用这个条件。此代码正在工作并显示框架,但在几帧之后它显示全黑框架。我认为错误在于接收数据包。

【问题讨论】:

  • TCP/IP 是流而不是数据包协议。在网络上,您会看到数据包,但在 API 级别,接收到的数据是连续的字节流。您需要解析这些字节以将接收到的数据分离和/或加入到相机帧中。
  • 我正在将该数据放入缓冲区
  • 如果相机连续发送数据没有任何具体区别,客户端不加区别地接收缓冲区。主要原因是recv函数只执行读取PC中设置的缓冲区的简单功能。
  • @Lakshraj 您能否发布更多关于您的实施的信息。 221184 是什么?是Maximum of Data 还是Size of per frame
  • 您必须实际实现相机正在使用的消息协议。 TCP 不是消息协议。

标签: c++ sockets tcp packet recv


【解决方案1】:

我收到的第一个数据包大小为 9 个字节,它打印正确,之后它总是打印 2000。所以谁能告诉我解决方案,我只得到实际数据有效负载的大小。

TCP 不是面向数据包的,而是面向流的传输协议。 TCP 中没有数据包的概念(可能除了 MTU)。如果您想在数据包中工作,您必须使用 UDP(实际上是面向数据包的,但默认情况下在顺序、丢弃等方面不可靠)或者您必须在 TCP 中实现数据包逻辑,即从收到后将数据流式传输并划分为逻辑数据包。

【讨论】:

  • 先生,我收到一帧的 221184 字节,它是分块的,所以我该如何实现它
  • @Lakshraj 您收到的字节来自多个帧(可能是最后一部分帧)。您需要解析字节以重新创建原始帧。并将任何剩余字节添加到下一个要接收的数据的开头。
  • 我也在做同样的事情,但是当我使用 while 循环打印 buf 时,它正在打印 ffffffcc
  • @Lakshraj TCP 是一个字节流。相机必须以这样一种方式对其数据进行构图,这样您就可以知道一条消息在哪里结束,而下一条消息在哪里开始。您的阅读代码必须考虑该框架。在 TCP 中只有 3 种方式可以构建消息: 1) 固定大小的消息;您一次可以读取 N 个字节。 2) 在消息前面加上它的大小;您可以先读取大小值,然后再读取后面指定的字节数。 3) 在消息之间使用唯一的分隔符。在遇到分隔符之前,您可以读取字节。
  • @Lakshraj 您的相机以哪种方式准确地构图数据?相机的 TCP 实现的细节应该在相机的文档中(你使用的是什么类型的相机?)。否则,Wireshark 究竟会为收到的前几个数据包的 TCP 负载显示什么?
【解决方案2】:
Size of per frame is : 221184 (fixed)   
Size of per recv is : 0 ~ 1514

我在这里的实现:

DWORD MakeFrame(int socket)
{
    INT nFrameSize = 221184;
    INT nSizeToRecv = 221184;
    INT nRecvSize = 2000;
    INT nReceived = 0;
    INT nTotalReceived = 0;
    BYTE byCamera[2000] = { 0 };    // byCamera size = nRecvSize
    BYTE byFrame[221184] = { 0 };   // byFrame size = nFrameSize

    while(0 != nSizeToRecv)
    {
        nRecvSize = min(2000, nSizeToRecv);
        nReceived = recv(socket, (char*)byCamera, nRecvSize, 0);

        memcpy_s(byFrame + nTotalReceived, nFrameSize, byCamera, nReceived);

        nSizeToRecv -= nReceived;
        nTotalReceived += nReceived;
    }

    // byFrame is ready to use.
    // ...
    // ...

    return WSAGetLastError();
}

【讨论】:

    猜你喜欢
    • 2017-02-27
    • 1970-01-01
    • 2015-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-24
    • 2018-06-06
    相关资源
    最近更新 更多