请选择 进入手机版 | 继续访问电脑版

[PHP编程] PHP实现WebSocket实例详解

[复制链接]
查看120 | 回复16 | 2021-9-13 21:23:34 | 显示全部楼层 |阅读模式

WebSocket 是什么?

摘抄网上的一些表明 :

WebSocket 协议是基于 TCP 的一种新的网络协议。它实现了欣赏 器与服务器全双工(full-duplex)通讯 ——答应 服务器主动 发送信息给客户端。

WebSocket 通讯 协议于2011年被 IETF 定为标准 RFC 6455,并被 RFC7936 所补充规范。

—— 百度百科

WebSocket 是一个持久化的协议,这是相对于 http 非持久化来说的。

举个简单的例子,http1.0 的生命周期是以 request 作为界定的,也就是一个 request,一个 response,对于 http 来说,本次 client 与 server 的会话到此竣事 ;而在 http1.1 中,轻微 有所改进,即添加了 keep-alive,也就是在一个 http 毗连 中可以举行 多个 request 哀求 和多个 response 担当 操作。然而在及时 通讯 中,并没有多大的作用,http 只能由 client 发起哀求 ,server 才能返回信息,即 server 不能主动 向 client 推送信息,无法满意 及时 通讯 的要求。而 WebSocket 可以举行 持久化毗连 ,即 client 只需举行 一次握手,成功后即可持续举行 数据通讯 ,值得关注的是 WebSocket 实现 client 与 server 之间全双工通讯 ,即 server 端有数据更新时可以主动 推送给 client 端。

PHP实现WebSocket实例详解

上图是一个演示client和server之间建立WebSocket毗连 时握手部分

client 建立 WebSocket 时向服务器端哀求 的信息

  1. GET /chat HTTP/1.1
  2.   Host: server.example.com
  3.   Upgrade: websocket //告诉服务器现在发送的是WebSocket协议
  4.   Connection: Upgrade
  5.   Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== //是一个Base64 encode的值,这个是浏览器随机生成的,用于验证服务器端返回数据是否是WebSocket助理
  6.   Sec-WebSocket-Protocol: chat, superchat
  7.   Sec-WebSocket-Version: 13
  8.   Origin: http://example.com
复制代码

服务器获取到 client 哀求 的信息后,根据 WebSocket 协议对数据举行 处理并返回,此中 要对 Sec-WebSocket-Key 举行 加密等操作

  1. HTTP/1.1 101 Switching Protocols
  2.   Upgrade: websocket //依然是固定的,告诉客户端即将升级的是Websocket协议,而不是mozillasocket,lurnarsocket或者shitsocket
  3.   Connection: Upgrade
  4.   Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= //这个则是经过服务器确认,并且加密过后的 Sec-WebSocket-Key,也就是client要求建立WebSocket验证的凭证
  5.   Sec-WebSocket-Protocol: chat
复制代码

PHP 服务端

  1. <?php
  2. if(($socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP)) < 0) {
  3. echo "socket_create() 失败的原因是:".socket_strerror($sock)."\n";
  4. }
  5. if(($ret = socket_bind($socket,'127.0.0.1','9090')) < 0) {
  6. echo "socket_bind() 失败的原因是:".socket_strerror($ret)."\n";
  7. }
  8. if(($ret = socket_listen($socket,3)) < 0) {
  9. echo "socket_listen() 失败的原因是:".socket_strerror($ret)."\n";
  10. }
  11. $all_sockets = [$socket]; // socket 集合
  12. do {
  13. $copy_sockets = $all_sockets; // 单独拷贝一份
  14. // 因为客户端是长连接,如果客户端非正常断开,服务端会在 socket_accept 阻塞,现在使用 select 非阻塞模式 socket
  15. if(socket_select($copy_sockets, $write, $except, 0) === false)
  16. exit('sosket_select error!');
  17. // 接收第一次 socket 连入,连入后移除服务端 socket
  18. if(in_array($socket, $copy_sockets)) {
  19. $client = socket_accept($socket);
  20. if($client) {
  21. $buf = socket_read($client, 1024);
  22. echo $buf;
  23. // 匹配 Sec-Websocket-Key 标识
  24. if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/i",$buf,$match)) {
  25. // 需要将 Sec-WebSocket-Key 值累加字符串,并依次进行 SHA-1 加密和 base64 加密
  26. $key = base64_encode(sha1($match[1] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',true));
  27. // 拼凑响应内容
  28. $res= "HTTP/1.1 101 Switching Protocol".PHP_EOL
  29. ."Upgrade: WebSocket".PHP_EOL
  30. ."Connection: Upgrade".PHP_EOL
  31. ."WebSocket-Location: ws://127.0.0.1:9090".PHP_EOL
  32. ."Sec-WebSocket-Accept: " . $key .PHP_EOL.PHP_EOL; // 注意这里,需要两个换行
  33. // 向客户端应答 Sec-WebSocket-Accept
  34. socket_write($client, $res, strlen($res));
  35. // 向客户端发送消息
  36. socket_write($client, buildMsg('socket ok'), 1024);
  37. // 加入客户端 socket
  38. $all_sockets[] = $client;
  39. }
  40. // 移除服务端 socket
  41. $key = array_search($socket, $copy_sockets);
  42. unset($copy_sockets[$key]);
  43. // socket_close($client);
  44. }
  45. }
  46. // 循环所有客户端 sockets
  47. foreach ($copy_sockets as $s) {
  48. // 获取客户端发给服务端的内容
  49. $buf = socket_read($s, 8024);
  50. echo strlen($buf).'---'.PHP_EOL;
  51. // 代表客户端主动关闭
  52. if(strlen($buf) < 9) {
  53. $key = array_search($s, $all_sockets);
  54. unset($all_sockets[$key]);
  55. socket_close($s);
  56. continue;
  57. }
  58. // 输出
  59. echo getMsg($buf).PHP_EOL;
  60. }
  61. }while(true);
  62. socket_close($socket);
  63. // 编码服务端向客户端发送的内容
  64. function buildMsg($msg) {
  65. $frame = [];
  66. $frame[0] = '81';
  67. $len = strlen($msg);
  68. if ($len < 126) {
  69. $frame[1] = $len < 16 ? '0' . dechex($len) : dechex($len);
  70. } else if ($len < 65025) {
  71. $s = dechex($len);
  72. $frame[1] = '7e' . str_repeat('0', 4 - strlen($s)) . $s;
  73. } else {
  74. $s = dechex($len);
  75. $frame[1] = '7f' . str_repeat('0', 16 - strlen($s)) . $s;
  76. }
  77. $data = '';
  78. $l = strlen($msg);
  79. for ($i = 0; $i < $l; $i++) {
  80. $data .= dechex(ord($msg{$i}));
  81. }
  82. $frame[2] = $data;
  83. $data = implode('', $frame);
  84. return pack("H*", $data);
  85. }
  86. // 解析客户端向服务端发送的内容
  87. function getMsg($buffer) {
  88. $res = '';
  89. $len = ord($buffer[1]) & 127;
  90. if ($len === 126) {
  91. $masks = substr($buffer, 4, 4);
  92. $data = substr($buffer, 8);
  93. } else if ($len === 127) {
  94. $masks = substr($buffer, 10, 4);
  95. $data = substr($buffer, 14);
  96. } else {
  97. $masks = substr($buffer, 2, 4);
  98. $data = substr($buffer, 6);
  99. }
  100. for ($index = 0; $index < strlen($data); $index++) {
  101. $res .= $data[$index] ^ $masks[$index % 4];
  102. }
  103. return $res;
  104. }
复制代码

客户端

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <script>
  7. // 创建一个Socket实例
  8. var socket = new WebSocket('ws://localhost:9090');
  9. // 打开Socket
  10. socket.onopen = function(event) {
  11. // 发送一个初始化消息
  12. socket.send("init msg");
  13. };
  14. socket.onmessage = function(event) {
  15. console.log('收到消息',event);
  16. };
  17. // 监听Socket的关闭
  18. socket.onclose = function(event) {
  19. console.log('关闭监听',event);
  20. };
  21. function send()
  22. {
  23. socket.send("client msg");
  24. }
  25. </script>
  26. </head>
  27. <body>
  28. <button onclick="send()">发送消息</button>
  29. </body>
  30. </html>
复制代码

运行测试:

Client

PHP实现WebSocket实例详解

Server

PHP实现WebSocket实例详解

到此这篇关于PHP实现WebSocket实例详解的文章就先容 到这了,更多干系 PHP实现WebSocket内容请搜索 脚本之家从前 的文章或继续欣赏 下面的干系 文章渴望 大家以后多多支持脚本之家!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

avatar 安夕萌mdj | 2021-9-14 06:34:17 | 显示全部楼层
今天是个特别的日子,值得纪念!
回复

使用道具 举报

avatar 李凯908 | 2021-9-20 15:14:48 | 显示全部楼层
很经典,收藏了!
回复

使用道具 举报

avatar 宿命958 | 2021-9-21 01:07:04 | 显示全部楼层
有钱、有房、有车,人人都想!
回复

使用道具 举报

avatar 上海庐冠计算机 | 2021-9-26 23:34:34 | 显示全部楼层
好东西,学习学习!
回复

使用道具 举报

avatar 小妖花满楼满fx | 2021-10-5 08:00:23 | 显示全部楼层
admin楼主给脑残下了定义!
回复

使用道具 举报

avatar xypkwg5156 | 2021-10-7 21:59:36 | 显示全部楼层
信admin楼主,得永生!
回复

使用道具 举报

avatar leefengme | 2021-10-9 22:17:59 | 显示全部楼层
今天上网不回帖,回帖就回精华帖!
回复

使用道具 举报

avatar 柳芽2017 | 2021-10-11 01:47:00 | 显示全部楼层
投admin楼主一票,不用谢哦!
回复

使用道具 举报

avatar 倪丹军 | 2021-10-11 08:33:42 | 显示全部楼层
求加金币!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则