swoole和websocket简单聊天室开发


Posted in PHP onNovember 18, 2017

首先,我想说下写代码的一些习惯,第一,任何可配置的参数或变量都要写到一个config文件中。第二,代码中一定要有日志记录和完善的报错并记录报错。言归正传,swoole应该是每个phper必须要了解的,它号称重新定义了php。此聊天室利用了swoole高并发并且异步非阻塞的特点提高了程序的性能。

首先,定义一个 swoole_lock swoole_websocket_server ,并且配置参数,具体参数详情可以去swoole官网查看。

public function start()
{
  $this->lock = new swoole_lock(SWOOLE_MUTEX);

  // 对文件或数组进行锁操作,已达到同步
  $this->server = new swoole_websocket_server($this->addr, $this->port);

  // swoole提供的Websocket Server
  $this->server->set(array(
   'daemonize' => 0,
   'worker_num' => 4,
   'task_worker_num' => 10,
   'max_request' => 1000,
   'log_file' => ROOT_PATH . 'storage\\logs\\swoole.log'  

  // swoole日志路径,必须是绝对路径
  ));

  $this->server->on('open', array($this, 'onOpen'));
  $this->server->on('message', array($this, 'onMessage'));
  $this->server->on('task', array($this, 'onTask'));
  $this->server->on('finish', array($this, 'onFinish'));
  $this->server->on('close', array($this, 'onClose'));

 // 启动服务
  $this->server->start();
}

当有客户端链接时,简单记录客户端的信息。

public function onOpen($server, $request)
  {
   $message = array(
    'remote_addr' => $request->server['remote_addr'],
    'request_time' => date('Y-m-d H:i:s', $request->server['request_time'])
   );
   write_log($message);
  }

当有客户端发送信息时,对信息进行处理。

public function onMessage($server, $frame)
  {
   $data = json_decode($frame->data);

   switch ($data->type) {
    case 'init':
    case 'INIT':
     $this->users[$frame->fd] = $data->message;、

   // 记录每个链接的信息,同样不要尝试打印出来看,因为你只能看到自己的链接信息
     $message = '欢迎' . $data->message . '加入了聊天室';
     $response = array(
      'type' => 1, // 1代表系统消息,2代表用户聊天
      'message' => $message
     );
     break;
    case 'chat':
    case 'CHAT':
     $message = $data->message;
     $response = array(
      'type' => 2, // 1代表系统消息,2代表用户聊天
      'username' => $this->users[$frame->fd],
      'message' => $message
     );
     break;
    default:
     return false;
   }

 // 将信息交给task处理
   $this->server->task($response);
  }

  public function onTask($server, $task_id, $from_id, $message)
  {
 // 迭代所有的客户端链接,将消息推送过去。(如果你尝试将 $this->server->connections 打印出来,那么你会发现他是空的。但当时用 foreach 去循环时,它确实有用。)
   foreach ($this->server->connections as $fd) {
    $this->server->push($fd, json_encode($message));
   }
   $server->finish( 'Task' . $task_id . 'Finished' . PHP_EOL);
  }

最后,当客户端断开链接时,利用锁机制,同步删除客户端信息,并记录日志。

public function onClose($server, $fd)
  {
   $username = $this->users[$fd];
   // 释放客户端,利用锁进行同步
   $this->lock->lock();
   unset($this->users[$fd]);
   $this->lock->unlock();

   if( $username ) {
    $response = array(
     'type' => 1, // 1代表系统消息,2代表用户聊天
     'message' => $username . '离开了聊天室'
    );
    $this->server->task($response);
   }


   write_log( $fd . ' disconnected');
  }

服务端完了,下面就是客户端,很简单,只需要用websocket链接就ok!

// websocket
  let address = 'ws://<?php echo CLIENT_CONNECT_ADDR . ':' . CLIENT_CONNECT_PORT ?>';
  let webSocket = new WebSocket(address);
  webSocket.onerror = function (event) {
   alert('服务器连接错误,请稍后重试');
  };
  webSocket.onopen = function (event) {
   if(!sessionStorage.getItem('username')) {
    setName();
   }else {
    username = sessionStorage.getItem('username')
    webSocket.send(JSON.stringify({
     'message': username,
     'type': 'init'
    }));
   }
  };
  webSocket.onmessage = function (event) {
   console.log(event);
   let data = JSON.parse(event.data);
   if (data.type == 1) {
    $('#chat-list2').append('<li class="ui-border-tb"><span class="username">系统消息:</span><span class="message">' + data.message + '</span></li>');
   } else if (data.type == 2) {
    $('#chat-list2').append('<li class="ui-border-tb"><span class="username">' + data.username + ':</span><span class="message">' + data.message + '</span></li>');
   }

  };
  webSocket.onclose = function (event) {
   alert('散了吧,服务器都关了');
  };

详细代码可以去我的github下载

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
初学CAKEPHP 基础教程
Nov 02 PHP
鸡肋的PHP单例模式应用详解
Jun 03 PHP
php实现执行某一操作时弹出确认、取消对话框
Dec 30 PHP
php实现的简单日志写入函数
Mar 31 PHP
php实现多城市切换特效
Aug 09 PHP
PHP接收json 并将接收数据插入数据库的实现代码
Dec 01 PHP
PHP信号量基本用法实例详解
Feb 12 PHP
thinkPHP使用pclzip打包备份mysql数据库的方法
Apr 30 PHP
谈谈PHP连接Access数据库的注意事项
Aug 12 PHP
搜索附近的人PHP实现代码
Feb 11 PHP
php对微信支付回调处理的方法
Aug 23 PHP
在Laravel 中实现是否关注的示例
Oct 22 PHP
php单元测试phpunit入门实例教程
Nov 17 #PHP
PHP开发之归档格式phar文件概念与用法详解【创建,使用,解包还原提取】
Nov 17 #PHP
PHP流Streams、包装器wrapper概念与用法实例详解
Nov 17 #PHP
PHP实现求两个字符串最长公共子串的方法示例
Nov 17 #PHP
PHP实现求解最长公共子串问题的方法
Nov 17 #PHP
php大小写转换函数(strtolower、strtoupper)用法介绍
Nov 17 #PHP
PHP 实现人民币小写转换成大写的方法及大小写转换函数
Nov 17 #PHP
You might like
全国FM电台频率大全 - 5 内蒙古自治区
2020/03/11 无线电
PHP中动态显示签名和ip原理
2007/03/28 PHP
非常全面的php日期时间运算汇总
2015/11/04 PHP
ThinkPHP实现更新数据实例详解(demo)
2016/06/29 PHP
PHP的中使用非缓冲模式查询数据库的方法
2017/02/05 PHP
JQuery 操作select标签实现代码
2010/05/14 Javascript
jQuery的显示和隐藏方法与css隐藏的样式对比
2013/10/18 Javascript
node.js中的console.warn方法使用说明
2014/12/09 Javascript
浅谈页面装载js及性能分析方法
2014/12/09 Javascript
JS运动框架之分享侧边栏动画实例
2015/03/03 Javascript
JavaScript中toString()方法的使用详解
2015/06/05 Javascript
Bootstrap模态窗口源码解析
2017/02/08 Javascript
ES6中Symbol类型用法实例详解
2017/04/06 Javascript
深入理解Angular.JS中的Scope继承
2017/06/04 Javascript
vue中axios的封装问题(简易版拦截,get,post)
2018/06/15 Javascript
javascript原型链学习记录之继承实现方式分析
2019/05/01 Javascript
Vue可自定义tab组件用法实例
2019/10/24 Javascript
详解Vue3 Teleport 的实践及原理
2020/12/02 Vue.js
vue中使用echarts的示例
2021/01/03 Vue.js
[10:14]2018DOTA2国际邀请赛寻真——paiN Gaming不仅为自己而战
2018/08/14 DOTA
Eclipse + Python 的安装与配置流程
2013/03/05 Python
python运行其他程序的实现方法
2017/07/14 Python
Python tkinter实现的图片移动碰撞动画效果【附源码下载】
2018/01/04 Python
对python数据切割归并算法的实例讲解
2018/12/12 Python
Python多进程方式抓取基金网站内容的方法分析
2019/06/03 Python
flask应用部署到服务器的方法
2019/07/12 Python
Python编写通讯录通过数据库存储实现模糊查询功能
2019/07/18 Python
PyCharm2018 安装及破解方法实现步骤
2019/09/09 Python
如何在 Django 模板中输出 &quot;{{&quot;
2020/01/24 Python
浅谈OpenCV中的新函数connectedComponentsWithStats用法
2020/07/05 Python
九年级数学教学反思
2014/02/02 职场文书
石油工程专业毕业生求职信
2014/04/13 职场文书
竞选体育委员演讲稿
2014/04/26 职场文书
学生偷窃检讨书
2014/09/25 职场文书
歌咏比赛口号大全
2015/12/25 职场文书
《月歌。》宣布制作10周年纪念剧场版《RABBITS KINGDOM THE MOVIE》
2022/04/02 日漫