概述
1.介绍
websocket介绍不用细说,这里主要给出服务器实现思路,下面直入主题。
websocket服务器跟正常的服务器区别在消息处理上,websocket在我们正常的数据中添加了websocket协议头,所以要拿到正常的数据需要先解析websocket协议,才能拿到实际内容,协议内容如下:
The following is websocket data frame:
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 ... |
+---------------------------------------------------------------+
协议详解请参考
http://www.cnblogs.com/caosiyang/archive/2012/08/14/2637721.html
不熟悉协议的话请尽量先熟悉一下协议。
2.协议解析
握手阶段主要是对客户端请求中Sec-WebSocket-Accept字段值的处理
服务器取该字段的值+258EAFA5-E914-47DA-95CA-C5AB0DC85B11来获取sha1值并base64返回给客户端,对应回应协议中的Sec-WebSocket-Key字段。
注意:sha1后需要对结果做特殊处理,实例代码如下
// create server key
string key =fieldMap["Sec-WebSocket-Key"];
key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
SHA1 sha;
unsigned int message_digest[5];
sha.Reset();
sha << key.c_str();
sha.Result(message_digest);
// convert sha1 hash bytes to network byte order because this sha1
// library works on ints rather than bytes
for (int i = 0; i < 5; i++) message_digest[i] = htonl(message_digest[i]);
key = base64_encode(reinterpret_cast<const unsigned char*>(message_digest),20);
至此握手完毕。(sha1和base64自行去网上查找)
解析数据帧:参考上面的协议详解就可大致能自行解析websocket协议了
贴上代码吧
typedef unsigned char byte;
int index = 0;
char buf[MAX_LENGTH];ZERO(buf);
byte bEof = ((byte)msg[0] >> 7) > 0; // is eof
byte bmask= ((byte)msg[1] & 0xF) > 0; // has mask
int pklen= ((byte)msg[1] & 0x7F);
index+=2;
if (pklen == 126)
{
pklen = ntohs(*(uint16*)(msg+index));
index += 2;
}
else
{
pklen = ntohl(*(ulong*)(msg+index));
index += 8;
}
// has mask
byte mask[4]; ZERO(mask);
if (bmask)
{
memcpy(&mask,&msg[index],4);
index += 4;
}
memcpy(buf, msg+index, pklen);
if (bmask)
{
for (int i = 0; i < pklen; ++i)
{
buf[i] = (buf[i] ^ mask[i%4]);
}
}
buf中就是我们需要的实际内容了。
服务器回应数据帧:(同样需要按照websoket协议封装发送的内容)
代码如下:
void WebSocketServer::sendtoclient(int sock, const char* msg, int len)
{
int sum = 0;
char outmsg[MAX_LENGTH]; ZERO(outmsg);
outmsg[sum++] = 130; // FIN+Binary
if (len < 126)
{
outmsg[sum++] = len;
}
else if(len > 125 && len <= 65535)
{
outmsg[sum++] = 126;
uint16 tmp = htons(len);
memcpy(&outmsg[sum], &tmp, 2);
sum += 2;
}
else
{
outmsg[sum++] = 127;
ulong tmp = htonl(len);
memcpy(&outmsg[sum], &tmp, 8);
sum += 8;
}
memcpy(&outmsg[sum], msg, len);
sum += len;
write(sock, outmsg, sum);
INFO("send to %d len%d", sock, sum);
}
websocket关闭连接时会先发一个opcode:1000的数据帧,客户端和服务器都需要回应才能正常关闭连接。
3.备注
在开发阶段可以使用Wireshark抓包工具抓包分析传输的数据是否正确。
最后
以上就是怕孤单树叶为你收集整理的websocket C/C++服务器应用的全部内容,希望文章能够帮你解决websocket C/C++服务器应用所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复