博客列表 >仿百度商桥项目-使用workerman进行websocket通信/模拟商桥群发消息

仿百度商桥项目-使用workerman进行websocket通信/模拟商桥群发消息

岂几岂几
岂几岂几原创
2021年03月22日 23:33:111776浏览

使用workerman进行websocket通信/模拟商桥群发消息

学习心得

  • 提供 websocket 通信服务的服务器, 像一个跟所有人保持通信的传声筒, 它可以接收来自客户端的消息, 也能主动给客户端发送消息. 而 http 通信, 服务器只能跟发送请求的客户端交互, 不能主动发送消息给客户端.

1. 使用workerman进行websocket通信

1.1. workerman的下载和简单开发实例说明

  1. 访问workerman官网,点击“下载”栏目,在“workerman内核(Linux Windows通用)”框中点击“下载ZIP压缩文件”开始下载workerman文件包,并解压缩(假设解压缩到Workerman目录中):
  2. 参考workerman说明文档中“简单开发实例”的实例二,创建wk_test.php文件,并拷贝实例二ws_test.php文件中的代码到创建的文件中:
  3. 在wk_test.php文件所在目录,用git batch启动workerman服务端:
  4. 打开chrome浏览器,按F12打开调试控制台,在Console一栏输入客户端给服务端发送消息的代码:

1.2. 实例中的细节说明

  • websocket 链接跟 http 链接的区别: http 链接在客户端向服务器发送请求, 服务器返回响应后, 链接就会断开; websocket 链接在链接成功后, 可以持续通信, 链接会一直保持.

  • workerman 应用在服务器中的位置跟 Apache , Nginx 相同. 即, web 服务器.

  • 使用 workerman 创建使用 websocket 通信的应用服务器的一般步骤:

    1. 创建一个 Worder 应用对象, 传入参数指定应用负责处理 websocket 通信. $ws_worker = new Worker("websocket://0.0.0.0:2000"); ; 其中的 0.0.0.0:2000 表示接受任意IP客户端发送到服务器 2000 端口的链接请求.
    2. 启动提供 websocket 通信的系统进程数. $ws_worker->count = 4; ;
    3. 指定收到客户端发送来数据后的处理数据的方法脚本: $ws_worker->onMessage = function($connection, $data) {...} ; 其中参数 $connection 是发送数据的客户端与服务器的 websocket 链接; $data 是客户端发送过来的数据.
    4. 指定当客户端断开链接时的处理脚本. $ws_worker->onClose = function($connection) {...} ; 其中参数 $connection 是即将关闭的 websocket 链接.
    5. 启动 Worker 应用.
    6. 服务端使用 websocket 链接的 send(消息字符串) 向该链接的客户端发送消息数据. $connection->send('hello!');
    7. Worder 对象的 connections 属性是当前与服务器保持通讯的 websocket 链接数组.
  • 客户端与提供 websocket 通信的服务器交互的一般步骤:

    1. 创建一个跟服务器进行 websocket 通信的链接: ws = new WebSocket("ws://127.0.0.1:2000"); . 其中 127.0.0.1 是客户端要与之创建 websocket 链接的服务器地址, 2000 是服务器监听链接和数据收发的端口号.
    2. 指定当连接创建成功时的回调处理方法, 一般链接创建成功后, 就发送唯一标识当前客户端信息的数据, 如保存在 cookie 中的 用户id 等. ws.onopen = function() {// 一般发送客户端的唯一标识给服务器存储 }
    3. 指定收到服务器返回的消息时的处理方法脚本. ws.onmessage = function(e) {// 收到服务器的消息了, 处理消息数据吧}
    4. 客户端同样使用 websocket 连接的 send(消息字符串) 方法向服务器发送数据.

2. 模拟商桥群发消息

  • 实现思路: 服务器类内置一个connections属性数组, connections 属性保存有所有成功跟客户端创建链接的连接对象. 当某个客户端给服务器发送消息时, 服务器遍历 connections 中链接对象, 给连接对象的客户端发送消息, 即可实现群发.

代码

  • 1- 服务端
  1. <?php
  2. use Workerman\Worker;
  3. require_once __DIR__ . '/workerman/Autoloader.php';
  4. // 注意:这里与上个例子不同,使用的是websocket协议
  5. $ws_worker = new Worker("websocket://0.0.0.0:2000");
  6. // 启动4个进程对外提供服务
  7. $ws_worker->count = 4;
  8. // 当接收到客户端发来的消息时的处理方法
  9. $ws_worker->onMessage = function($connection, $data)
  10. {
  11. // 发送消息的连接id
  12. $message['from_id'] = $connection->id;
  13. // 消息内容
  14. $message['msg'] = $data
  15. // 转成json字符串
  16. $jsonStr = json_encode($message);
  17. // 遍历当前所有的链接对象, 给连接对象对应的客户端发送数据
  18. foreach($ws_worker->connection as $conn) {
  19. $connection->send($jsonStr);
  20. }
  21. }
  22. // 运行worker
  23. Worker::runAll();
  • 2- 客户端
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>"百度商桥"客户端</title>
  7. <link rel="stylesheet" href="/static/plugin/layui/css/layui.css" media="all">
  8. <script src="/static/plugin/layui/layui.js"></script>
  9. <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script>
  10. <style>
  11. * {
  12. margin: 0;
  13. padding: 0;
  14. box-sizing: border-box;
  15. }
  16. body {
  17. background-color: #fafafa;
  18. }
  19. .im {
  20. width: 400px;
  21. height: 520px;
  22. background-color: wheat;
  23. margin: 40px auto;
  24. padding: 10px;
  25. }
  26. .im .history {
  27. background-color: white;
  28. border: 1px solid #aaa;
  29. width: 100%;
  30. height: 290px;
  31. padding: 5px;
  32. overflow-y: auto;
  33. }
  34. .im .inputing {
  35. background-color: white;
  36. border: 1px solid #aaa;
  37. width: 100%;
  38. height: 150px;
  39. margin-top: 10px;
  40. padding: 5px;
  41. outline: none;
  42. }
  43. .im .btn-area {
  44. width: 100%;
  45. text-align: right;
  46. margin-top: 10px;
  47. }
  48. .msg-box-friend {
  49. padding: 10px;
  50. width: 75%;
  51. margin: 5px auto 0 5px;
  52. background-color: lightblue;
  53. border: 1px solid #ccc;
  54. border-radius: 5px;
  55. /* overflow-x: wordwrap; */
  56. white-space:normal;
  57. }
  58. .msg-box-me {
  59. padding: 10px;
  60. width: 75%;
  61. margin: 5px 5px 0 auto;
  62. background-color: wheat;
  63. border: 1px solid #ccc;
  64. border-radius: 5px;
  65. /* overflow-x: wordwrap; */
  66. white-space:normal;
  67. }
  68. </style>
  69. </head>
  70. <body>
  71. <div class="im">
  72. <div class="history">
  73. </div>
  74. <!-- contenteditable="true", 这个div就可编辑了 -->
  75. <div class="inputing" contenteditable="true">
  76. </div>
  77. <div class="btn-area">
  78. <span class="layui-btn layui-btn-success" onclick="send()">发送</span>
  79. </div>
  80. </div>
  81. </body>
  82. <script>
  83. layui.use(['layer'], function() {
  84. layer = layui.layer;
  85. });
  86. // 假设服务端ip为127.0.0.1
  87. ws = new WebSocket("ws://127.0.0.1:2000");
  88. /* 当客户端连通服务器端的时候 */
  89. ws.onopen = function() {
  90. // ...
  91. };
  92. ws.onmessage = function(e) {
  93. // alert("收到服务端的消息:" + e.data);
  94. var receive = JSON.parse(e.data);
  95. var str = "<div class='msg-box-friend'>"+receive.from_id+"说: "+receive.msg+"</div>";
  96. $(str).appendTo('.history');
  97. };
  98. function send() {
  99. // 消息框
  100. var str = "<div class='msg-box-me'>我说: "+$('.inputing').html()+"</div>";
  101. var data = {};
  102. // 标识此次发送的数据是发送消息
  103. data.type='msg';
  104. // 标识是从客服端发的
  105. data.group = 'admin'
  106. // 标识私聊的对象id,0标识群发. DEL_客户连接时由系统随机分配客服小姐姐, 不需要手动指定了
  107. // data.sendId = 0;
  108. // 要发送的消息
  109. data.msg = $('.inputing').html();
  110. // 在消息历史中显示发送的消息
  111. $(str).appendTo('.history');
  112. // 发送JSON格式的数据
  113. ws.send(JSON.stringify(data));
  114. $('.inputing').html('');
  115. }
  116. </script>
  117. </html>
声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议