问题描述
正如我在上一个问题(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帧(仅 。)