如何在C/C++的socket中接收一个整数数组?

3

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

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

这是正确的方法吗?read()函数返回的值是否可能不是int类型的倍数? 如果这种方法不正确,那么接收整数数组的正确方法是什么?

3个回答

1
在Linux中,您可以使用MSG_WAITALL选项来进行recv()操作,这使得函数等待传入数据的完整长度。
或者(适用于所有平台),您也可以编写一个通用的接收函数来接收指定数量的字节,例如下面这个函数(假定套接字未设置为非阻塞;需要包括<stdint.h>)。
/// \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...
}

1
您是正确的,read可能无法返回您请求的所有数据,特别是如果它连接到网络套接字。 read不一定会返回一个sizeof(int)的倍数值。如果您想使用这种(手动)接收数据的方法,我建议您计算字节数而不是sizeof(int)(这可以是4或8,具体取决于您的系统)。比这更容易的方法是使用类似Protocol Buffers的东西,它允许您为数据包定义数据格式并快速轻松地进行序列化/反序列化。 (定义一个仅包含整数数组的消息,让protobuf处理其他所有内容。)

1
应该注意的是,在出现错误或中断的情况下,或者如果正在阻塞并且已经传递了非阻塞套接字,则read()也可能返回-1,这在OP的源代码中没有考虑到,因此后一种情况会完全破坏算法。另外,read()返回0的情况,即另一端关闭了连接,也没有被考虑在内,会导致无限循环。 - alk

0

你说得对 - 不能保证读取的数据大小是sizeof(int)的倍数。

你可能会收到的最小大小是一个char

从网络接收整数(显然也适用于发送整数到网络)时,还有其他问题,比如字节序,你应该注意这些问题。

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

此外,如果您正在通过网络进行发送接收,请注意像TCP这样的协议是基于流的,即它们只是发送字符流,您需要实现一些方法来检测消息的结束并将其格式化为您的需求。两种常见的方法是将消息的长度作为标头发送或使用特殊字符(如'\n')来表示消息的结束。另外,由于您正在发送一个数组,因此可以使用类似于“|”来分隔元素的内容。
因此,示例消息可以是:“1 | 100 | 239 | 23 | \n”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接