【问题标题】:Why is Winsock recvfrom() buffer returning 'E'?为什么 Winsock recvfrom() 缓冲区返回“E”?
【发布时间】:2021-04-02 15:09:05
【问题描述】:

我正在尝试使用 Winsock 接收数据包,并且我能够从 recvfrom() 命令获得返回,但是当我尝试打印缓冲区中保存的数据时,我只得到 E。

这是我使用 recvfrom 命令的地方:

    i = 0;
    while (i < 25) {
        data_len = recvfrom(raw_socket, rcvbuf, sizeof(rcvbuf), 0, (SOCKADDR*)&sender_addr, &sender_addr_size);

        std::cout << "Iteration: " << (i);
        printf("\nReceived packet from %s:%d\n", inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port));
        printf("Length of bytes received: %d\n", data_len);
        printf("Data: %s\n", rcvbuf);
        std::cout << "\n\n";
        i = i + 1;
    }  

运行代码时的示例返回:
迭代次数:21
隐藏 IP 收到的数据包:0
收到的字节长度:1385
数据:E

这不是缓冲区大小的错误,在网上搜索了几个小时后,我找不到任何描述我的问题的东西。 如果有人知道这里发生了什么,我将非常感谢您的解释甚至更好的修复。

其他可能有用的代码:

    char rcvbuf[10000];    
...
    // create a raw socket
    raw_socket = socket(AF_INET, SOCK_RAW, 0);
    if (raw_socket == INVALID_SOCKET) {
        printf("Error at socket(): %ld\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }
...
    // Bind the IPv4 address to the socket
    if0.sin_addr.S_un.S_addr = inet_addr(local_ip);
    if0.sin_family = AF_INET;
    if0.sin_port = htons(14996);;
    if (bind(raw_socket, (SOCKADDR*)&if0, sizeof(if0)) == SOCKET_ERROR) {
        printf("bind() failed with error code %d\n", WSAGetLastError());
        return -1;
    }
    else printf("bind() is OK!\n");

感谢每一位帮助过的人 :) 我为打印缓冲区中的二进制数据所做的更改(不考虑字节序):

    // receive all packages in a while loop
    std::cout << "Connected on IPv4 Address: " << local_ip << "\n";
    i = 0;
    while (i < 2) {
        data_len = recvfrom(raw_socket, rcvbuf, sizeof(rcvbuf), 0, (SOCKADDR*)&sender_addr, &sender_addr_size);

        std::cout << (i);
        printf("\nReceived packet from %s:%d\n", inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port));
        printf("Length of bytes received: %d\n", data_len);
        printf("Data: ");
        //std::cout.write(rcvbuf, data_len);

        std::string s = rcvbuf;
        for (int i2 = 0; i2 < data_len;) {
            std::cout << std::bitset<8>(s[i2]) << " ";
            i2 = i2 + 1;
        }

        std::cout << "\n--------------------------\n";
        memset(rcvbuf, 0, 10000);
        i = i + 1;
    }

【问题讨论】:

  • 这可能是二进制数据恰好有 0 作为第二个字节。回想一下,printf("Data: %s\n", rcvbuf); 假定 rcvbuf 指向一个以 nul 结尾的字符串,因此会在遇到的第一个零字节处停止打印。
  • 啊是的,这是有道理的,我已将字符串类型更改为其他类型,并且得到了不同的结果。谢谢。
  • 无需将rcvbuf 转换为std::string 即可将其打印出来。可以直接打印rcvbuf的内容。特别是因为您的转换存在与原始 printf 相同的错误 - 假设 rcvbuf 是一个以空字符结尾的字符串,而实际上它不是。

标签: c++ visual-studio winapi networking winsock


【解决方案1】:

您没有使用正确的输出函数来查看数据。您正在使用假定字符串数据以空值结尾的函数:

printf("Data: %s\n", rcvbuf);

这将打印rcvbuf 中的内容,直到到达空终止符。这一点很可能少于data_len 个字符。

要正确打印数据,可以使用std::cout.write()函数:

std::cout.write(rcvbuf, data_len);

【讨论】:

  • std::string s = rcvbuf; 也是如此。它需要一个以空字符结尾的字符串作为输入。请改用std::string s(rcvbuf, data_len);
猜你喜欢
  • 1970-01-01
  • 2014-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多