前提:笔者在开发server程序时,要求websocket与server连接
websocket的机制是在第一次连接时进行握手协议,协议通过,才可以进行正常的通信,否则websocket就会断开连接;
下面就是websocket第一次发送的握手包:
GET / HTTP/1.1\r\n
Host: 192.168.5.24:17913\r\n
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0\r\n
Accept: */*\r\n
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2\r\n
Accept-Encoding: gzip, deflate\r\n
Sec-WebSocket-Version: 13\r\n
Origin: http://127.0.0.1:8848\r\n
Sec-WebSocket-Extensions: permessage-deflate\r\n
Sec-WebSocket-Key: tepG0DQZtEJ7MLbw7kbewA==\r\n
Connection: keep-alive, Upgrade\r\n
Pragma: no-cache\r\nCache-Control: no-cache\r\n
Upgrade: websocket\r\n\r\n
那需要对websocket发送来的第一个数据进行处理(判断是否是第一个包,可以通过开头GET来进行判断,可能不是非常严谨),获取Sec-WebSocket-Key的值(也就是上面的ikLk+bBgZDQRPTOBAzGsBg==),然后对此进行解析。
解析的方法是在key上加上固定字符串“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”,再进行sha1解码及base64编码,然后打包发送给websocket客户端。
返回的握手包如下:
HTTP/1.1 101 Switching Protocols\r\n
Connection: upgrade\r\n
Sec-WebSocket-Accept: mhW8gChbFWgUKJxpzcbPlcwJxcw=\r\n
Upgrade: websocket\r\n\r\n
代码如下:
void rcvReadData()
{
QByteArray data_ = this->readAll();//socket接收数据
if(!_firstConnect)//第一个包
{
_firstConnect = true;
QString qstr_ = data_;//包数据转化成QString
QString key_ = "";
key_ = getKey(qstr_);
if(key_ == "-1")
{
//自定义处理
}
else if(key_ == "-2")
{
//自定义处理
}
else
{
//处理key
char request[1024] = ""; //请求信息
respondHandshake(request,key_.toStdString());
QByteArray array_(request);
write(array_);//发送数据给websocket客户端
}
}
else
{
//接下来包在此不做处理,需要涉及到websocket协议的解包
}
}
/**
*获取Sec-WebSocket-Key的值,QT实现
*/
QString getKey(QString qstr)
{
int i = qstr.indexOf("GET");
if(i < 0)
{
return "-1";
}
int j = qstr.indexOf("Sec-WebSocket-Key");
if(j < 0)
{
return "-2";
}
QString key = qstr.mid(j + 19, 24);
return key;
}
/**
*获取Sec-WebSocket-Key的值,C++实现
*/
string getKey(string str)
{
int i = str.find("GET");
if(i < 0)
{
return "-1";
}
int j = str.find("Sec-WebSocket-Key");
if(j < 0)
{
return "-2";
}
string key = str.substr(j + 19, 24);
return key;
}
void respondHandshake(char *request, string clientkey)
{
strcat(request, "HTTP/1.1 101 Switching Protocols\r\n");
strcat(request, "Connection: upgrade\r\n");
strcat(request, "Sec-WebSocket-Accept: ");
string server_key = clientkey;
server_key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
SHA1 sha;
unsigned int message_digest[5];
cout <<"server_key:"<< server_key << endl;
sha.Reset();
sha << server_key.c_str();
sha.Result(message_digest);
for (int i = 0; i < 5; i++) {
message_digest[i] = htonl(message_digest[i]);
}
base64 base64_;
server_key = base64_.base64_encode(reinterpret_cast<const unsigned char*>(message_digest), 20);
server_key += "\r\n";
strcat(request, server_key.c_str());
strcat(request, "Upgrade: websocket\r\n\r\n");
}
至于代码中出现的sha1以及base64,,可以在以下链接中找到,本文就不再复制粘贴了:
C++简单实现一个websocket服务器_c++ websocket server-CSDN博客
以上只是对握手协议进行了实现,但是实际使用中,在握手完成后,对于websocket发送来的数据,还需要进行解析,才可以获取数据,而且在解析时,还需要处理粘包半包等问题,留待下一篇文章进行阐述。
解析发送的数据,见我下一章:C++实现WebSocket解析协议
结尾:
只为记录,只为分享! 愿所写能对你有所帮助。不忘记点个赞,谢谢~