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中创建并处理图象
Oct 09 PHP
PHP设计模式之解释器模式的深入解析
Jun 13 PHP
php获取远程图片体积大小的实例
Nov 12 PHP
Zend Framework实现留言本分页功能(附demo源码下载)
Mar 22 PHP
CentOS下搭建PHP环境与WordPress博客程序的全流程总结
May 07 PHP
PHP图片水印类的封装
Jul 06 PHP
PHP微信公众号开发之微信红包实现方法分析
Jul 14 PHP
php+mysql开发的最简单在线题库(在线做题系统)完整案例
Mar 30 PHP
PHP开发实现快递查询功能详解
Apr 08 PHP
Laravel Validator 实现两个或多个字段联合索引唯一
May 08 PHP
Yii2处理密码加密及验证的方法
May 12 PHP
laravel实现登录时监听事件,添加登录用户的记录方法
Sep 30 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
zen cart新进商品的随机排序修改方法
2010/09/10 PHP
php目录操作实例代码
2014/02/21 PHP
php实现保存submit内容之后禁止刷新
2014/03/19 PHP
详解yii2使用多个数据库的案例
2017/06/16 PHP
PHP实现验证码校验功能
2017/11/16 PHP
js no-repeat写法 背景不重复
2009/03/18 Javascript
JS中==与===操作符的比较
2009/03/21 Javascript
jQuery live( type, fn ) 委派事件实现
2009/10/11 Javascript
javaScript 动态访问JSon元素示例代码
2013/08/30 Javascript
快速使用node.js进行web开发详解
2017/04/26 Javascript
JavaScript使用Ajax上传文件的示例代码
2017/08/10 Javascript
mpvue写一个CPASS小程序的示例
2018/09/04 Javascript
一个因@click.stop引发的bug的解决
2019/01/08 Javascript
Vue CLI4 Vue.config.js标准配置(最全注释)
2020/06/05 Javascript
[57:55]完美世界DOTA2联赛PWL S3 Magma vs Phoenix 第二场 12.12
2020/12/16 DOTA
使用Python解析JSON数据的基本方法
2015/10/15 Python
Python模拟鼠标点击实现方法(将通过实例自动化模拟在360浏览器中自动搜索python)
2017/08/23 Python
pyqt5 实现在别的窗口弹出进度条
2019/06/18 Python
使用python serial 获取所有的串口名称的实例
2019/07/02 Python
python selenium 执行完毕关闭chromedriver进程示例
2019/11/15 Python
python网络编程socket实现服务端、客户端操作详解
2020/03/24 Python
Django调用百度AI接口实现人脸注册登录代码实例
2020/04/23 Python
使用python脚本自动生成K8S-YAML的方法示例
2020/07/12 Python
一款基于css3和jquery实现的动画显示弹出层按钮教程
2015/01/04 HTML / CSS
CSS实现进度条和订单进度条的示例
2020/11/05 HTML / CSS
HTML5语义化元素你真的用对了吗
2019/08/22 HTML / CSS
台湾良兴购物网:EcLife
2019/12/01 全球购物
Theflamel意大利:女士奢华服装、鞋子和配件
2020/01/11 全球购物
什么是接口(Interface)?
2013/02/01 面试题
优秀的茶餐厅创业计划书
2014/01/03 职场文书
中学生运动会入场词
2014/02/12 职场文书
实验教师岗位职责
2014/02/13 职场文书
春节晚会主持词
2014/03/24 职场文书
公司业务员管理制度
2015/08/05 职场文书
2016大学生优秀志愿者事迹材料
2016/02/25 职场文书
Python获取字典中某个key的value
2022/04/13 Python