💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
  这两天在研究websocekt技术,看到了一些很棒的类库。原本打算在直接研究workerman的,后来想想,websocket的基础还没怎么去理解呢,直接搞那个不太好,先研究一下自己怎么去写一个简单的socket服务器。 ![](https://box.kancloud.cn/7f89366de2a4cbf16f5296cfe7eaf908_725x672.)   WebSocket protocol 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。在这个协议提出之前,我想大家去做一些类似于IM这样的应用的时候,由于http是短连接性质的,大家肯定会用ajax轮询的方式去定时的请求服务器,以获得数据。当然这样的缺点也是很明显的。HTTP request 的header是非常长的,里面包含的有用数据可能只是一个很小的值,这样会占用很多的带宽。那怎么去解决这种应用呢?看看websocket的做法。   握手协议 在实现websocket连线过程中,需要通过浏览器发出websocket连线请求,然后服务器发出回应,这个过程通常称为“握手” (handshaking)。 本文只介绍一种版本的websocket握手方式。   握手的原理大致如下: 客户端请求web socket连接时,会向服务器端发送握手请求 var ws = new WebSocket('ws://127.0.0.1:8090'); 请求内容大致如下: 复制代码 GET / HTTP/1.1 Host: 192.168.0.10:8080 Connection: Upgrade Pragma: no-cache Cache-Control: no-cache Upgrade: websocket Origin: null Sec-WebSocket-Version: 13 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 Accept-Encoding: gzip, deflate, sdch Accept-Language: zh-CN,zh;q=0.8 Sec-WebSocket-Key: VR+OReqwhymoQ21dBtoIMQ== Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits 复制代码 请求包说明: * 必须是有效的http request 格式; * HTTP request method 必须是GET,协议应不小于1.1 如: Get / HTTP/1.1; * 必须包括Upgrade头域,并且其值为”websocket”; * 必须包括”Connection” 头域,并且其值为”Upgrade”; * 必须包括”Sec-WebSocket-Key”头域,其值采用base64编码的随机16字节长的字符序列; * 如果请求来自浏览器客户端,还必须包括Origin头域 。 该头域用于防止未授权的跨域脚本攻击,服务器可以从Origin决定是否接受该WebSocket连接; * 必须包括”Sec-webSocket-Version” 头域,当前值必须是13; * 可能包括”Sec-WebSocket-Protocol”,表示client(应用程序)支持的协议列表,server选择一个或者没有可接受的协议响应之; * 可能包括”Sec-WebSocket-Extensions”, 协议扩展, 某类协议可能支持多个扩展,通过它可以实现协议增强; * 可能包括任意其他域,如cookie. 服务器端响应如下: 1 2 3 4 HTTP/1.1 101 Web Socket Protocol Handshake Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: Y+Te7S7wQJC0FwXumEdGbv9/Mek= 应答包说明: *必须包括Upgrade头域,并且其值为”websocket”; *必须包括Connection头域,并且其值为”Upgrade”; *必须包括Sec-WebSocket-Accept头域,其值是将请求包“Sec-WebSocket-Key”的值,与”258EAFA5- E914-47DA-95CA-C5AB0DC85B11″这个字符串进行拼接,然后对拼接后的字符串进行sha-1运算,再进行base64编码,就是 “Sec-WebSocket-Accept”的值; *应答包中冒号后面有一个空格; *最后需要两个空行作为应答包结束。 请注意:258EAFA5- E914-47DA-95CA-C5AB0DC85B11 这一串加密的字串是固定的,不可更改,否则会握手失败。客户端的请求头实际上是一个http请求,我们只要从头部匹配出 Sec-WebSocket-Key 并且按照固定加密返回即可。 获取 Sec-WebSocket-Key 方法: 复制代码 1 public function getKey($req) { 2 $key = null; 3 if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $req, $match)) { 4 $key = $match[1]; 5 } 6 return $key; 7 } 复制代码 加密返回方法: 1 public function encry($req){ 2 $key = $this->getKey($req); 3 $mask = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; 4 5 return base64_encode(sha1($key . $mask, true)); 6 } 拼装握手方法: 复制代码 1 public function dohandshake($socket, $req){ 2 // 获取加密key 3 $acceptKey = $this->encry($req); 4 $upgrade = "HTTP/1.1 101 Switching Protocols\r\n" . 5 "Upgrade: websocket\r\n" . 6 "Connection: Upgrade\r\n" . 7 "Sec-WebSocket-Accept: " . $acceptKey . "\r\n" . 8 "\r\n"; 9 10 // 写入socket 11 socket_write($socket, $upgrade.chr(0), strlen($upgrade.chr(0))); 12 } 复制代码 参考文章:http://blog.csdn.net/edwingu/article/details/44040961,http://www.jb51.net/article/48019.htm 标签: phpwebsocket, websocket握手 workerman