【问题标题】:Using recv() to receive chunks of a message使用 recv() 接收消息块
【发布时间】:2020-05-07 20:44:57
【问题描述】:

我正在使用 WebSockets。我创建了一个小型测试客户端,它拆分消息,然后逐块发送。例如这样的消息:

PROTOCOL HTTP ACTION UPDATE

可以发送为

PROTOC

然后作为一个块

OL HTT

作为另一种方法,而不是将完整的消息以PROTOCOL HTTP ACTION UPDATE 的形式发送到一个块中,这也是一种可能性。

所以我接收信息的方式必须反映这一点。目前,我不确定如何使用recv,因为一条消息将被分成多个部分并发送出去。

这是我正在尝试的,但我不确定这是否是正确的方法。接收时是否应始终将缓冲区大小保持为 200?我应该什么时候退出循环?

void recv_all(){
            char rec_buffer[200]
            while(1) {
              ssize_t bytes_rec = recv(socket_fd, rec_buffer, sizeof(rec_buffer),0);

            }
}

【问题讨论】:

  • recv() 从套接字读取任意原始字节。它没有 WebSockets 或任何其他协议的概念。您需要读取原始字节并根据RFC 6455 手动重建 WebSocket 消息,然后才能重建跨越多个 WebSocket 消息的文本数据块。您为什么不使用为您处理此问题的 WebSocket 库?
  • 你可以尝试使用像github.com/zaphoyd/websocketpp这样的网络套接字解析器
  • 另请注意,recv() 是低级读取,实际上,当 flags 参数为 0 时,它等价于 read()。唯一的区别是是否消费了未决的数据报。 recv() 会,read() 不会。所以recv 只是从流中读取原始字节——您将其指定为第一个参数。

标签: c websocket recv


【解决方案1】:

您可以使用对read() 的调用返回的值,然后使用strcat() 将消息的各个部分重新粘合在一起。

根据 OP,消息以 \r\n 结尾,这是一个如何将消息作为多个数据包读取的示例。

char *message = malloc( MAX_MSG_LEN +1 );
if( ! message )
{
    perror( "malloc failed" );
    exit( EXIT_FAILURE );
}

// implied else, malloc successful

recv_buf[0] = '\0';
size_t msgLen = 0;
int done = 0;

while( msgLen < MAX_MSG_LEN && !done)
{
    ssize_t byteCount = read( socket_fd, message, MAX_MSG_LEN );

    if( ! byteCount )
    {
        // handle error of sender closing the socket
    }

    else if( byteCount < 0 )
    {
        // handle I/O error
    }

    else
    {
        if( msgLen+byteCount > sizeof( recv_buf ) )
        {
            // handle error of message too long
        }

        else
        {
            message[ byteCount ] = '\0';
            strcat( recv_buf, message );
            msgLen += byteCount;
            if( memcmp( recv_buf[msgLen-2], "\r\n", 2 ) == 0 )
            {
                 done = 1;
            }
        }
    }
}
free( message );

注意:我没有运行上面的例子,所以可能需要做一些调试。

【讨论】:

  • 消息的结尾用\n\r表示。用recv 检测这个的方法是什么?
  • 函数:recv() 对数据包的内容一无所知。相反,在每次调用recv() 之后,使用memcmp() 将当前接收到的数据包的结尾与\r\n 进行比较,当找到匹配项时,该数据包就是消息的结尾
【解决方案2】:

(stream) 套接字处理字节流,而不是消息。因此,它们提供了一种在端点之间获取字节流的方法,仅此而已。如果您想要某种“消息”,则需要处理字节流以查找消息边界并自己将其分解为消息。

执行此操作的常用方法是使用缓冲区,例如 C FILE 对象或 C++ 流缓冲区。您安排从套接字读取字节到缓冲区,然后检查缓冲区中是否有完整的消息,通常通过查找消息终止符/边界标记(例如 \r\n 或只是 \n)。如果有,则从缓冲区中删除(仅)该消息。

在 C 中使用 POSIX 很容易做到——您可以使用 fdopen 打开带有套接字描述符的文件,然后使用 fgets 或 getline 将消息读取到换行符。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-14
    • 1970-01-01
    • 2021-08-15
    • 2012-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多