前言
这是一篇系列文章,文章列表:
- php原生socket实现客户端与服务端数据传输
- php原生socket之IO多路复用以及实现web服务器
- php原生socket实现websocket聊天室
websocket介绍
webSocket 协议是一种网络通信协议,在 2008 年诞生,2011 年成为国际标准,RFC6455 定义了它的通信标准,如今所有浏览器都已支持了该协议。webSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工[1]
webSocket 约定了一个通信协议的规范,通过握手机制,客户端(浏览器)和服务器(webserver)之间能建立一个类似 tcp 的连接,从而方便 cs 通信。
为什么需要websocket
HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了 请求 => 响应 模型,通信请求仅能由客户端发起,服务端对请求做出应答处理,这种通信模型有一个弊端:无法实现服务端主动向客户端发起消息。传统的 HTTP 请求,其并发能力都是依赖同时发起多个 TCP 连接访问服务器实现的而 websocket 则允许我们在一条 ws 连接上同时并发多个请求,即在 A 请求发出后 A 响应还未到达,就可以继续发出 B 请求。由于 TCP 的慢启动特性,以及连接本身的握手损耗,都使得 websocket 协议的这一特性有很大的效率提升。

特点
- 建立在 TCP 协议之上,服务端的实现相对比较容易
- 与 HTTP 协议有良好的兼容性,默认端口也是 80 和 443,并且握手阶段采用 HTTP 协议,因此握手时不容易被屏蔽,能通过各种 HTTP 代理服务器。
- 数据格式比较轻量,性能开销小,通信高效。
- 可以发送文本,也可以发送二进制数据。
- 没有同源限制,客户端可以与任意服务器进行通信。
- 协议标识符是 ws(如果加密则为 wss),服务地址就是 URL。
PHP实现websocket
客户端与服务端握手
websocket 协议在连接前需要握手[2]
基于 flash 的握手协议(不建议)
基于 md5 加密方式的握手协议
较早的握手方法,有两个 key,使用 md5 加密
基于 sha1 加密方式的握手协议
当前主要的握手协议,本文将以此协议为主
- 获取客户端上报的
Sec-WebSocket-key - 拼接
key+258EAFA5-E914-47DA-95CA-C5AB0DC85B11 - 对字符串做
SHA1计算,再把得到的结果通过base64加密,最后再返回给客户端
- 获取客户端上报的
客户端请求信息如下:
GET /chat |
客户端需返回如下数据:
101 Switching Protocols |
我们根据此协议通过 PHP 方式实现:
|
相关语法解释可参考 之前的文章,本文章不做详细介绍。
使用前端测试,打开我们的任意浏览器控制台(console)输入以下内容,返回的 websocket 对象的 readyState 为 1 即为握手成功,此为前端内容,本文不多做介绍,详情可参考 菜鸟教程:
console.log(new WebSocket('ws://192.162.2.166:8888')); |
发送数据与接收数据
使用 websocket 协议传输协议需要遵循特定的格式规范,详情请参考 https://datatracker.ietf.org/doc/html/rfc6455#section-5.2
为了方便,这里直接贴出加解密代码,以下代码借鉴与 workerman 的 src/Protocols/Websocket.php 文件:
// 解码客户端发送的消息 |
我们修改刚才 客户端与服务端握手 阶段的代码,修改后全代码全文如下,该段代码实现了将客户端发送的消息转为大写后返回给客户端(当然只是为了演示):
|
使用 在线测试工具 进行测试,可以看到消息已经可以正常发送接收,接下来的文章将继续优化代码,实现简易聊天室,敬请关注:
实现web聊天室
我们紧接着上文的代码继续优化,以实现简易的web聊天室
多路复用
其实就是加一下 socket_select() 函数 😂 ,本文就不写原理与语法了,详情可参考 之前的文章,以下代码修改自前文 发送数据与接收数据
... |
实现聊天室
最终成果演示
我们将上述代码改造成类,并在类变量储存用户信息,添加消息处理等逻辑,最后贴出代码,建议保存下来自己尝试一下,也许会有全新的认知,后端代码:
|
前端代码如下(前端内容不在本文讨论范围之内,具体可参考 菜鸟教程):
|


