WorkerMan中如何向某个特定客户端发送数据

使用worker来做服务器,没有用GatewayWorker,如何实现向指定用户推送消息?

  1. <?php
  2. use Workerman\Worker;
  3. use Workerman\Connection\TcpConnection;
  4. require_once __DIR__ . '/vendor/autoload.php';
  5. // 初始化一个worker容器,监听1234端口
  6. $worker = new Worker('websocket://workerman.net:1234');
  7. // ====这里进程数必须必须必须设置为1====
  8. $worker->count = 1;
  9. // 新增加一个属性,用来保存uid到connection的映射(uid是用户id或者客户端唯一标识)
  10. $worker->uidConnections = array();
  11. // 当有客户端发来消息时执行的回调函数
  12. $worker->onMessage = function(TcpConnection $connection, $data)
  13. {
  14. global $worker;
  15. // 判断当前客户端是否已经验证,即是否设置了uid
  16. if(!isset($connection->uid))
  17. {
  18. // 没验证的话把第一个包当做uid(这里为了方便演示,没做真正的验证)
  19. $connection->uid = $data;
  20. /* 保存uid到connection的映射,这样可以方便的通过uid查找connection,
  21. * 实现针对特定uid推送数据
  22. */
  23. $worker->uidConnections[$connection->uid] = $connection;
  24. return $connection->send('login success, your uid is ' . $connection->uid);
  25. }
  26. // 其它逻辑,针对某个uid发送 或者 全局广播
  27. // 假设消息格式为 uid:message 时是对 uid 发送 message
  28. // uid 为 all 时是全局广播
  29. list($recv_uid, $message) = explode(':', $data);
  30. // 全局广播
  31. if($recv_uid == 'all')
  32. {
  33. broadcast($message);
  34. }
  35. // 给特定uid发送
  36. else
  37. {
  38. sendMessageByUid($recv_uid, $message);
  39. }
  40. };
  41. // 当有客户端连接断开时
  42. $worker->onClose = function(TcpConnection $connection)
  43. {
  44. global $worker;
  45. if(isset($connection->uid))
  46. {
  47. // 连接断开时删除映射
  48. unset($worker->uidConnections[$connection->uid]);
  49. }
  50. };
  51. // 向所有验证的用户推送数据
  52. function broadcast($message)
  53. {
  54. global $worker;
  55. foreach($worker->uidConnections as $connection)
  56. {
  57. $connection->send($message);
  58. }
  59. }
  60. // 针对uid推送数据
  61. function sendMessageByUid($uid, $message)
  62. {
  63. global $worker;
  64. if(isset($worker->uidConnections[$uid]))
  65. {
  66. $connection = $worker->uidConnections[$uid];
  67. $connection->send($message);
  68. }
  69. }
  70. // 运行所有的worker(其实当前只定义了一个)
  71. Worker::runAll();

说明:

以上例子可以针对uid推送,虽然是单进程,但是支持个10W在线是没问题的。

注意这个例子只能单进程,也就是$worker->count 必须是1。要支持多进程或者服务器集群的话需要Channel组件完成进程间通讯,开发也非常简单,可以参考Channel组件集群推送例子一节。

如果希望在其它系统中推送消息给客户端,可以参考在其它项目中推送一节