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 相关文章推荐
PhpMyAdmin中无法导入sql文件的解决办法
Jan 08 PHP
发款php蜘蛛统计插件只要有mysql就可用
Oct 12 PHP
采用PHP函数memory_get_usage获取PHP内存清耗量的方法
Dec 06 PHP
通过缓存数据库结果提高PHP性能的原理介绍
Sep 05 PHP
解析php DOMElement 操作xml 文档的实现代码
May 10 PHP
Yii配置文件用法详解
Dec 04 PHP
php判断表是否存在的方法
Jun 18 PHP
PHP递归实现层级树状展开
Apr 01 PHP
简单概括PHP的字符串中单引号与双引号的区别
May 07 PHP
PHP array_key_exists检查键名或索引是否存在于数组中的实现方法
Jun 13 PHP
PHP未登录自动跳转到登录页面
Dec 21 PHP
php使用imagecopymerge()函数创建半透明水印
Jan 25 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
PHP XML error parsing SOAP payload on line 1
2010/06/17 PHP
PHP统计目录中文件以及目录中目录大小的方法
2016/01/09 PHP
json 定义
2008/06/10 Javascript
jQuery LigerUI 使用教程表格篇(1)
2012/01/18 Javascript
js控制input框只读实现示例
2014/01/20 Javascript
jquery增加和删除元素的方法
2015/01/14 Javascript
javascript禁止访客复制网页内容的实现代码
2015/08/05 Javascript
jQuery实现的网页右下角tab样式在线客服效果代码
2015/10/23 Javascript
Jquery ajax 同步阻塞引起的UI线程阻塞问题
2015/11/17 Javascript
jquery判断复选框是否选中进行答题提示特效
2015/12/10 Javascript
基于JS实现EOS隐藏错误提示层代码
2016/04/25 Javascript
详解Bootstrap各式各样的按钮(推荐)
2016/12/13 Javascript
js实现显示手机号码效果
2017/03/09 Javascript
Angular简单验证功能示例
2017/12/22 Javascript
Vue实现todolist删除功能
2018/06/26 Javascript
javascript中的event loop事件循环详解
2018/12/14 Javascript
Jquery实现获取子元素的方法分析
2019/08/24 jQuery
基于Vue el-autocomplete 实现类似百度搜索框功能
2019/10/25 Javascript
Vue的状态管理vuex使用方法详解
2020/02/05 Javascript
[02:40]2014DOTA2 国际邀请赛中国区预选赛 四大豪门抵达华西村
2014/05/23 DOTA
Python实现备份文件实例
2014/09/16 Python
利用QT写一个极简单的图形化Python闹钟程序
2015/04/07 Python
python读取txt文件,去掉空格计算每行长度的方法
2018/12/20 Python
对Python3.x版本print函数左右对齐详解
2018/12/22 Python
Python读取csv文件分隔符设置方法
2019/01/14 Python
pytorch 改变tensor尺寸的实现
2020/01/03 Python
pytorch载入预训练模型后,实现训练指定层
2020/01/06 Python
全球销量第一生发产品:Viviscal
2017/12/21 全球购物
土木工程实习生自我鉴定
2013/09/19 职场文书
周年庆典主持词
2014/04/02 职场文书
师范学院毕业生求职信
2014/06/24 职场文书
财会专业大学生求职信
2014/09/26 职场文书
教你如何用Python实现人脸识别(含源代码)
2021/06/23 Python
彻底解决MySQL使用中文乱码的方法
2022/01/22 MySQL
Nginx工作模式及代理配置的使用细节
2022/03/21 Servers
公历12个月名称的由来
2022/04/12 杂记