手写WebSocket服务器-02-相关代码
1.基础通信
需要声明的是,这个所谓的websocket服务器,本质上仍然是一个tcp服务器,跟web服务器原理一致,只不过web服务器实现的是http协议,websocket服务器实现的是websocket协议。
关于基础通信部分的代码,我们在web服务器系列文章中已经详细做过说明,因此这里不再重复讲解。
下面我们直接讲业务部分。
2.握手数据
前一篇文章提到,正式开始websocket协议通信前, 需要先经历一个握手的过程,在这个过程中,服务器收到的数据是:
服务器应答的数据是:
服务器收到数据后,执行了如下代码:
第一段主要是做下基本的正确性判断,确保握手请求是用http的GET协议发出的。
第二段是从请求文本中提取出了如下信息:
这个信息是浏览器端生成的一个字符串,服务端需要经过一系列的处理,将其生成下面的字符串返回给浏览器端,以验证基本的通信安全性:
处理的过程是怎样的呢?
可以看到,服务器先是将客户单发来的字符串与一个固定的字符串进行拼接(这个固定的串叫GUID)。
然后调用SHA1算法,为这个新的拼接字符串生成摘要。
然后将这个摘要用base64进行编码,就最终生成了要返回给浏览器的字符串。
服务器将这个字符串打包成HTTP应答,直接发送给客户端,就完成了websocekt协议的握手过程。
后续双方就使用正常的websocket协议进行通信了。
3.正常数据
前面的例子提到,浏览器发送了一个字符串hello给服务器,服务器又回了一个hello字符串给浏览器,那么这个过程是如何实现的呢?
首先第一步,是把从网络上收到的字节流(buf,len),调用wsc_clnt_unpack函数,解析成websocket帧,解析过程如下:
这个过程基本上是按照websocket协议逐字段解析的过程,比较繁琐,这里我们不再详细探讨(下图附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 ... |
+---------------------------------------------------------------+
我们只需知道,最终他会把解析结果放在这样一个结构体中就行了:
其中data是实际的有效数据(即本例中的hello),len是有效数据的长度(本例中是5),fin表示这一批数据是不是收完了。
继续看解析代码:
可以看到,这里有一个大包拼小包的过程,目的是方便我们处理。
拼接完成后,调用wsc_clnt_handle,在这里,我们就可以实现具体的业务处理逻辑。在本例中,就是我们怎样处理收到的“hello”这个字符串。
在本例中,我们没有做任何处理,只是把收到的hello字符串,打包成websocket协议后发送了出去。
协议打包的过程也比较简单:
基本上就是填个头,拷贝下有效数据。
完。