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 相关文章推荐
php学习 字符串课件
Jun 15 PHP
兼容性最强的PHP生成缩略图的函数代码(修改版)
Jan 18 PHP
PHP 图片上传代码
Sep 13 PHP
PHP随机字符串生成代码(包括大小写字母)
Jun 24 PHP
浅谈PHP调用Webservice思路及源码分享
Jun 04 PHP
php smarty truncate UTF8乱码问题解决办法
Jun 13 PHP
php通过array_merge()函数合并关联和非关联数组的方法
Mar 18 PHP
一个PHP实现的轻量级简单爬虫
Jul 08 PHP
详解php的socket通信
Aug 11 PHP
php提高网站效率的技巧
Sep 29 PHP
PHP共享内存使用与信号控制实例分析
May 09 PHP
PHP数组常用函数实例小结
Aug 20 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
Yii2创建控制器(createController)方法详解
2016/07/23 PHP
PHP缩略图生成和图片水印制作
2017/01/07 PHP
PHP实现登录验证码校验功能
2018/05/17 PHP
jquery固定底网站底部菜单效果
2013/08/13 Javascript
ff下JQuery无法监听input的keyup事件的解决方法
2013/12/12 Javascript
JavaScript字符串对象slice方法入门实例(用于字符串截取)
2014/10/16 Javascript
jQuery使用之处理页面元素用法实例
2015/01/19 Javascript
AngularJS ng-bind-html 指令详解及实例代码
2016/07/30 Javascript
js实现鼠标拖动功能
2017/03/20 Javascript
基于javascript 显式转换与隐式转换(详解)
2017/12/15 Javascript
Angular2 父子组件通信方式的示例
2018/01/29 Javascript
Vue js 的生命周期(看了就懂)(推荐)
2019/03/29 Javascript
微信小程序 轮播图实现原理及优化详解
2019/09/29 Javascript
vscode 调试 node.js的方法步骤
2020/09/15 Javascript
详解nginx配置vue h5 history去除#号
2020/11/09 Javascript
[41:54]2018DOTA2亚洲邀请赛 4.1 小组赛A组加赛 TNC vs Liquid
2018/04/03 DOTA
Python中的yield浅析
2014/06/16 Python
编写Python脚本批量下载DesktopNexus壁纸的教程
2015/05/06 Python
解决python3中的requests解析中文页面出现乱码问题
2019/04/19 Python
Python常用扩展插件使用教程解析
2020/11/02 Python
CSS3中的content属性使用示例
2015/07/20 HTML / CSS
加拿大高尔夫超市:Golf Town
2018/01/12 全球购物
意大利高端时尚买手店:Stefania Mode
2018/03/01 全球购物
计算机专业毕业生的自我评价
2013/11/18 职场文书
《手指教学》反思
2014/02/14 职场文书
政府信息公开实施方案
2014/05/09 职场文书
廉洁教育学习材料
2014/05/19 职场文书
护林防火标语
2014/06/27 职场文书
感恩老师演讲稿600字
2014/08/28 职场文书
检讨书范文500字
2015/01/28 职场文书
初中毕业生自我评价
2015/03/02 职场文书
出国留学自荐信模板
2015/03/06 职场文书
2015小学毕业班工作总结
2015/07/21 职场文书
2019暑假学生安全口号
2019/06/27 职场文书
Python爬虫中urllib3与urllib的区别是什么
2021/07/21 Python
vue css 相对路径导入问题级踩坑记录
2022/06/05 Vue.js