【问题标题】:How to receive an integer arrray in C/C++ socket?如何在 C/C++ 套接字中接收整数数组?
【发布时间】:2013-04-19 22:31:55
【问题描述】:

在接收整数数组时,需要检查接收数据的字节数。 比如接收长度为100的整数数组时:

int count = 0;
int msg[100];
while(count < 100 * sizeof(int)){
    count += read(fd, msg + count / sizeof(int), 100 * sizeof(int) - count);
}

这是正确的方法吗? read() 会返回一个不是 sizeof(int) 倍数的值吗? 如果这不正确,那么接收整数数组的正确方法是什么?

【问题讨论】:

    标签: c sockets recv


    【解决方案1】:

    在 Linux 上,您可以为 recv() 使用 MSG_WAITALL 选项,这使函数等待传入数据的完整给定长度。

    作为替代方案(适用于所有平台),您还可以编写一个通用接收函数来接收给定数量的字节,例如这个(假设套接字未设置为非阻塞;需要包括&lt;stdint.h&gt;):

    /// \brief Receives a block of data of the specified size
    /// \param sk Socket for incoming data
    /// \param data Pointer to input buffer
    /// \param len Number of bytes to read
    /// \return Number of bytes received (same as len) on success, -1 on failure
    int block_recv(const int sk, uint8_t* data, unsigned int len)
    {
        int i, j = 0;
    
        while (len > 0) {
            i = recv(sk, (char*) data, len, 0);
            if (i <= 0) {
                return -1;
            }
            data += i;
            len -= i;
            j += i;
        }
    
        return j;
    }
    

    然后你可以调用它来接收你的整数缓冲区:

    if (block_recv(fd, (uint8_t*) msg, sizeof(msg)) != sizeof(msg)) {
        fprintf(stderr, "Error receiving integer buffer...\n");
        // whatever error handling you need...
    }
    

    【讨论】:

      【解决方案2】:

      您说得对,read 可能不会返回您请求的所有数据,尤其是。如果它连接到网络套接字。 read 不一定会返回 sizeof(int) 倍数的值。如果您想使用这种(手动)方法来接收数据,我可能会建议您计算字节数而不是 sizeof(int)s(根据您的系统可以是 4 或 8)。比这样做更容易的是使用Protocol Buffers 之类的东西,它允许您为数据包定义数据格式并快速轻松地序列化/反序列化它们。 (定义一个只包含整数数组的消息,让 protobuf 处理其他所有事情。)

      【讨论】:

      • 应该注意,如果发生错误或中断,或者如果即将阻塞并已通过非阻塞套接字 read() 也可能返回 -1 ,在OP的消息来源,所以这种较慢的情况会完全搞砸算法。同样read()返回0的情况,即另一端关闭了连接,也不考虑在内,会导致死循环。
      【解决方案3】:

      你是对的 - 不能保证 read 会返回大小是 sizeof(int) 的倍数的数据。 您可能收到的最小尺寸是char。 还有其他问题,例如receiving integers from across a network 时的字节顺序(显然也适用于sending integers across a network),您应该注意。

      由于这些原因,更简单的解决方案是使用char[] 而不是int[] 来存储消息,然后将其复制到int[]。如果您担心效率,请先向自己证明这是一个瓶颈(分析您的代码),然后再担心优化代码。

      另外,如果您在网络上使用 sending 和 recving,请注意 TCP 等协议是基于流的,即它们只是发送字符流,您需要实现某种检测结束的方法消息并根据您的需要对其进行格式化。两种常见的方法是将消息的长度作为标头发送,或者使用像'\n' 这样的特殊字符来表示消息的结束。此外,由于您要发送一个数组,您可以使用类似 '|'分隔元素。

      因此示例消息可以是:“1|100|239|23|\n”

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多