C使用libcurl获取websocket标头字段

问题描述

正如我在上一个问题(here中提到的那样),我试图获取websocket数据包的标头字段,特别是操作码。

正如我从RFC 6455 Sec 5.2中所读到的,一个Websocket就像休假:

 0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-------+-+-------------+-------------------------------+
     |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
     |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
     |N|V|V|V|       |S|             |   (if payload len==126/127)   |
     | |1|2|3|       |K|             |                               |
     +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
     |     Extended payload length continued,if payload len == 127  |
     + - - - - - - - - - - - - - - - +-------------------------------+
     |                               |Masking-key,if MASK set to 1  |
     +-------------------------------+-------------------------------+
     | Masking-key (continued)       |          Payload Data         |
     +-------------------------------- - - - - - - - - - - - - - - - +
     :                     Payload Data continued ...                :
     + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
     |                     Payload Data continued ...                |
     +---------------------------------------------------------------+

由于我只对提交的操作码感兴趣,所以我创建了一个结构作为休假;

struct websocketheader {
    uint32_t fin:1;
    uint32_t res1:1;
    uint32_t res2:1;
    uint32_t res3:1;
    uint32_t opcode:4;
    uint32_t mask:1;
    uint32_t payload_len:7;

};

如果我没有错的话

curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,write_data);
curl_easy_setopt(curl,CURLOPT_WRITEDATA,p_para);

这两行将传入的数据包传递给名为p_para作为用户数据指针的回调函数write_data。

我的write_data函数如下;


static size_t write_data(void* ptr,size_t size,size_t nmemb,void *stream)
{

    struct thread_para *p_thread = (struct thread_para*)stream;
    if (p_thread) { 
        struct websocketheader wsh; 
        memcpy(&wsh,ptr,sizeof(struct websocketheader));
        switch (wsh.opcode)
        {
        case CWS_OPCODE_CONTINUATION:
            printf("opcode: continuation\n");
            break;
        case CWS_OPCODE_TEXT:
            printf("opcode text\n");
            break;
        case CWS_OPCODE_BINARY:
            printf("opcode binary\n");
        case CWS_OPCODE_CLOSE:
            printf("opcode close\n");
            break;
        case CWS_OPCODE_PING: 
            printf("opcode ping\n");
            break;
        case CWS_OPCODE_PONG:
            printf("opcode pong\n");        
        default:
            printf("UnkNown opcode\n");
            break;
        }

        pthread_mutex_lock(&p_thread->lock);
        p_thread->Now += size * nmemb;
        pthread_mutex_unlock(&p_thread->lock);
                 
    }
    return size * nmemb;
}

我期望正确地将前16位写入到我的结构中,但打印结果显示情况并非如此。我目前正在打印随机操作码,这表明我无法正确读取操作码。

正如我在上一个问题中提到的那样,我对有效负载的兴趣为零,因为它们是垃圾,并且因为我可以通过size * nmemb从libcurl获得总长度,所以我也对websocket标头的有效负载长度字段不感兴趣。我不知道自己在做什么错,而且我对如何使用钻头的知识也知之甚少。

如果您能指出我做错了什么,并且还提出其他建议以不同的方式完成工作,我将不胜感激。

解决方法

不幸的是,您不能简单地做到这一点。

您已经假定在该回调中始终至少获得size * nmemb个字节,但事实并非如此。您得到{{1}}个字节。 TCP / IP是一种流协议。

您需要将接收到的字节添加到缓冲区中,然后在足够的字节数时解析websocket帧(仅 。)