例子1

(要求Workerman版本>=3.3.0)

基于Worker的多进程分组推送系统

  1. use Workerman\Worker;
  2. use Workerman\Connection\TcpConnection;
  3. require_once __DIR__ . '/vendor/autoload.php';
  4. $channel_server = new Channel\Server('0.0.0.0', 2206);
  5. $worker = new Worker('websocket://0.0.0.0:1234');
  6. $worker->count = 8;
  7. // 全局群组到连接的映射数组
  8. $group_con_map = array();
  9. $worker->onWorkerStart = function(){
  10. // Channel客户端连接到Channel服务端
  11. Channel\Client::connect('127.0.0.1', 2206);
  12. // 监听全局分组发送消息事件
  13. Channel\Client::on('send_to_group', function($event_data){
  14. $group_id = $event_data['group_id'];
  15. $message = $event_data['message'];
  16. global $group_con_map;
  17. var_dump(array_keys($group_con_map));
  18. if (isset($group_con_map[$group_id])) {
  19. foreach ($group_con_map[$group_id] as $con) {
  20. $con->send($message);
  21. }
  22. }
  23. });
  24. };
  25. $worker->onMessage = function(TcpConnection $con, $data){
  26. // 加入群组消息{"cmd":"add_group", "group_id":"123"}
  27. // 或者 群发消息{"cmd":"send_to_group", "group_id":"123", "message":"这个是消息"}
  28. $data = json_decode($data, true);
  29. var_dump($data);
  30. $cmd = $data['cmd'];
  31. $group_id = $data['group_id'];
  32. switch($cmd) {
  33. // 连接加入群组
  34. case "add_group":
  35. global $group_con_map;
  36. // 将连接加入到对应的群组数组里
  37. $group_con_map[$group_id][$con->id] = $con;
  38. // 记录这个连接加入了哪些群组,方便在onclose的时候清理group_con_map对应群组的数据
  39. $con->group_id = isset($con->group_id) ? $con->group_id : array();
  40. $con->group_id[$group_id] = $group_id;
  41. break;
  42. // 群发消息给群组
  43. case "send_to_group":
  44. // Channel\Client给所有服务器的所有进程广播分组发送消息事件
  45. Channel\Client::publish('send_to_group', array(
  46. 'group_id'=>$group_id,
  47. 'message'=>$data['message']
  48. ));
  49. break;
  50. }
  51. };
  52. // 这里很重要,连接关闭时把连接从全局群组数据中删除,避免内存泄漏
  53. $worker->onClose = function(TcpConnection $con){
  54. global $group_con_map;
  55. // 遍历连接加入的所有群组,从group_con_map删除对应的数据
  56. if (isset($con->group_id)) {
  57. foreach ($con->group_id as $group_id) {
  58. unset($group_con_map[$group_id][$con->id]);
  59. }
  60. if (empty($group_con_map[$group_id])) {
  61. unset($group_con_map[$group_id]);
  62. }
  63. }
  64. };
  65. Worker::runAll();

测试 (假设都是本机127.0.0.1运行)

1、运行服务端

  1. php start.php start
  2. Workerman[del.php] start in DEBUG mode
  3. ----------------------- WORKERMAN -----------------------------
  4. Workerman version:3.4.2 PHP version:7.1.3
  5. ------------------------ WORKERS -------------------------------
  6. user worker listen processes status
  7. liliang ChannelServer frame://0.0.0.0:2206 1 [OK]
  8. liliang none websocket://0.0.0.0:1234 12 [OK]
  9. ----------------------------------------------------------------
  10. Press Ctrl-C to quit. Start success.

2、客户端连接服务端

打开chrome浏览器,按F12打开调试控制台,在Console一栏输入(或者把下面代码放入到html页面用js运行)

  1. // 假设服务端ip为127.0.0.1,测试时请改成实际服务端ip
  2. ws = new WebSocket('ws://127.0.0.1:1234');
  3. ws.onmessage = function(data){console.log(data.data)};
  4. ws.onopen = function() {
  5. ws.send('{"cmd":"add_group", "group_id":"123"}');
  6. ws.send('{"cmd":"send_to_group", "group_id":"123", "message":"这个是消息"}');
  7. };