经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » PHP » 查看文章
基于swoole实现多人聊天室
来源:cnblogs  作者:我爱读活法  时间:2019/11/11 9:02:38  对本文有异议

核心的swoole代码

基本的cs(client-sercer)结构不变,这里利用的是redis的哈希和set来储存和分组;从而达到了分组,统计,定时推送等功能;最后利用onclose事件来剔除断开的连接,全部代码如下:(没做前端,就不展示了)

核心的swoole ws.php

  1. <?php
  2. namespace app\common;
  3. require_once 'Predis.php';
  4. require_once 'Task.php';
  5. /**
  6. * socket面向对象的编译
  7. */
  8. class Ws
  9. {
  10. CONST HOST='0.0.0.0';
  11. CONST PORT='9501';
  12. public $ws=null;
  13. public $getmsg=null;
  14. public $server=null;
  15. public function __construct()
  16. {
  17. $this->ws=new \swoole_websocket_server(self::HOST,self::PORT);
  18. $this->ws->set([
  19. //启动task必须要设置其数量
  20. 'worker_num' => 4,
  21. 'task_worker_num' => 2,
  22. // 'heartbeat_check_interval' => 5,
  23. // 'heartbeat_idle_time' => 10,
  24. ]);
  25. //监听新端口
  26. $this->server=$this->ws->listen("127.0.0.1", 9502, SWOOLE_SOCK_TCP);
  27. //关闭websocket模式
  28. $this->server->set([
  29. 'open_websocket_protocol' => false,
  30. ]);
  31. $this->ws->on("start", [$this, 'onStart']);
  32. $this->ws->on('open',[$this,'onopen']);
  33. $this->server->on("receive", [$this, 'onReceive']);
  34. $this->ws->on('task',[$this,'onTask']);
  35. $this->ws->on('finish',[$this,'onFinish']);
  36. $this->ws->on('message',[$this,'onmessage']);
  37. $this->ws->on('close',[$this,'onclose']);
  38. $this->server->on("close", [$this, 'oncloses']);
  39. $this->ws->start();
  40. }
  41. //监听数据接收事件
  42. public function onReceive($serv, $fd, $from_id, $data)
  43. {
  44. $shuju=json_decode($data,ture);
  45. // print_r($shuju).PHP_EOL;
  46. if (empty($shuju['data'])) {
  47. $this->ws->push(Predis::getInstance()->get('fd'), $data);
  48. }else{
  49. if (empty($shuju['msg'])) {
  50. //执行异步任务
  51. $this->ws->task($shuju);
  52. }else{
  53. $push_arr=Predis::getInstance()->hvals($shuju['data']);
  54. // echo "集群是:".print_r($push_arr);
  55. foreach ($push_arr as $v) {
  56. $this->ws->push($v, $shuju['msg']);
  57. }
  58. }
  59. }
  60. }
  61. /**
  62. * 设置进程名,为后续平滑重启进程
  63. * @param $server
  64. */
  65. public function onStart($server) {
  66. swoole_set_process_name("live_master");
  67. }
  68. /**
  69. 监听开启事件的回调
  70. */
  71. public function onopen($server, $request)
  72. {
  73. print_r("这时的fd是:",$request->fd);
  74. Predis::getInstance()->set('fd',$request->fd);
  75. }
  76. /**
  77. 监听接收事件的回调
  78. */
  79. public function onmessage($server, $frame)
  80. {
  81. $server->push($frame->fd, "{$frame->data}");
  82. }
  83. /**
  84. 监听关闭事件的回调
  85. */
  86. public function onclose($ser, $fd)
  87. {
  88. print_r("你好,我的{$fd}\n");
  89. //退出并删除多余的分组fd
  90. $group=Predis::getInstance()->sMembers('group');
  91. foreach ($group as $v) {
  92. $fangjian=Predis::getInstance()->hgetall($v);
  93. foreach ($fangjian as $k => $vv) {
  94. if ($fd == $vv) {
  95. Predis::getInstance()->hdel($v,$k);
  96. }
  97. }
  98. }
  99. }
  100. public function oncloses($ser, $fd)
  101. {
  102. print_r("这个是client{$fd}\n");
  103. }
  104. /**
  105. * $serv 服务
  106. * $task_id 任务ID,由swoole扩展内自动生成,用于区分不同的任务
  107. * $src_worker_id $task_id和$src_worker_id组合起来才是全局唯一的,不同的worker进程投递的任务ID可能会有相同
  108. * $data 是任务的内容
  109. */
  110. public function onTask($serv,$task_id,$src_worker_id,$data)
  111. {
  112. //引入任务
  113. $obj = new Task;
  114. $method = $data['data'];
  115. $arr = $data['arr'];
  116. //发布具体的任务
  117. $flag = $obj->$method($arr, $serv);
  118. return $flag; // 告诉worker
  119. }
  120. /**
  121. * $task_id 是任务的ID
  122. * $data 是任务处理的结果内容
  123. */
  124. public function onFinish($serv,$task_id,$data)
  125. {
  126. print_r($data).'/n';
  127. }
  128. }
  129. new Ws();

分发任务task.php

  1. <?php
  2. /**
  3. * 代表的是 swoole里面 后续 所有 task异步 任务 都放这里来
  4. * Date: 18/3/27
  5. * Time: 上午1:20
  6. */
  7. namespace app\common;
  8. // include 'Predis.php';
  9. class Task {
  10. //异步创建房间
  11. public function chuangjian($data,$serv)
  12. {
  13. $time=$data['time']*1000;
  14. swoole_timer_after($time, function() use($data){
  15. //创建房间(修改拍卖商品状态)
  16. self::post("https://code.77wx.cn/index/index/in");
  17. });
  18. }
  19. //进入房间并缓存信息
  20. public function jingru($data,$serv)
  21. {
  22. $fd=Predis::getInstance()->get('fd');
  23. //加入分组
  24. Predis::getInstance()->hset($data['name'],$data['uid'],$fd);
  25. //加入组集合
  26. Predis::getInstance()->sadd('group',$data['name']);
  27. }
  28. public function post($url,$params=false,$ispost=0)
  29. {
  30. $httpInfo = array();
  31. $ch = curl_init();
  32. curl_setopt( $ch, CURLOPT_HTTP_VERSION , CURL_HTTP_VERSION_1_1 );
  33. curl_setopt( $ch, CURLOPT_USERAGENT , 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22' );
  34. curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT , 30 );
  35. curl_setopt( $ch, CURLOPT_TIMEOUT , 30);
  36. curl_setopt( $ch, CURLOPT_RETURNTRANSFER , true );
  37. if( $ispost )
  38. {
  39. curl_setopt( $ch , CURLOPT_POST , true );
  40. curl_setopt( $ch , CURLOPT_POSTFIELDS , $params );
  41. curl_setopt( $ch , CURLOPT_URL , $url );
  42. }
  43. else
  44. {
  45. if($params){
  46. curl_setopt( $ch , CURLOPT_URL , $url.'?'.$params );
  47. }else{
  48. curl_setopt( $ch , CURLOPT_URL , $url);
  49. }
  50. }
  51. //执行
  52. $response = curl_exec( $ch );
  53. if ($response === FALSE) {
  54. //echo "cURL Error: " . curl_error($ch);
  55. return false;
  56. }
  57. $httpCode = curl_getinfo( $ch , CURLINFO_HTTP_CODE );
  58. $httpInfo = array_merge( $httpInfo , curl_getinfo( $ch ) );
  59. //关闭url请求
  60. curl_close( $ch );
  61. return json_decode($response,1);
  62. }
  63. }

客户端 client.php

  1. <?php
  2. namespace app\common;
  3. class Client
  4. {
  5. public $msg='';
  6. public $data=[];
  7. public function lianjie(){
  8. $cli = new \swoole_client(SWOOLE_SOCK_TCP);
  9. //判断连接状态(同步连接模式)
  10. $res=$cli->connect('127.0.0.1', 9502);
  11. if (empty($res)) {
  12. return "连接失败";
  13. }
  14. if (!empty($this->data)) {
  15. //发送消息给server
  16. $rel=$cli->send(json_encode($this->data));
  17. }else{
  18. //发送消息给server
  19. $rel=$cli->send($this->msg);
  20. }
  21. if (!empty($rel)) {
  22. return $rel;
  23. }else{
  24. return flash;
  25. }
  26. }
  27. }

控制器index.php

  1. <?php
  2. namespace app\index\controller;
  3. use app\common\Client;
  4. use app\common\Predis;
  5. use app\common\Sql;
  6. use app\index\model\User;
  7. class Index
  8. {
  9. //创建房间(添加拍卖倒计时)
  10. public function chuangjian()
  11. {
  12. $data['time']=input("time");
  13. $data['id']=input("id");
  14. $cli = new Client();
  15. $cli->data = [
  16. 'data' => 'chuangjian',
  17. 'arr' => $data
  18. ];
  19. return $cli->lianjie();
  20. }
  21. //点击添加哈希(进入房间)
  22. public function jingru()
  23. {
  24. $data['name']=input("name");
  25. $data['uid']=input("uid");
  26. $cli = new Client();
  27. $cli->data = [
  28. 'data' => 'jingru',
  29. 'arr' => $data
  30. ];
  31. return $cli->lianjie();
  32. }
  33. //本房间推送(出价格成功并推送)
  34. public function pushfan()
  35. {
  36. $data['fan']=input("fan");
  37. $cli = new Client();
  38. $cli->data = [
  39. 'data' => $data['fan'],
  40. 'msg' => "恭喜用户111,喜当爹!!!!"
  41. ];
  42. return $cli->lianjie();
  43. }
  44. //时间结束并指定推送
  45. public function zhiding()
  46. {
  47. $data['fan']=input("fan");
  48. $cli = new Client();
  49. $cli->data = [
  50. 'data' => $data['fan'],
  51. 'msg' => "恭喜用户111,喜当爹!!!!"
  52. ];
  53. return $cli->lianjie();
  54. }
  55. }

完事!

原文链接:http://www.cnblogs.com/wadhf/p/11827834.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号