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 20 PHP
适用于抽奖程序、随机广告的PHP概率算法实例
Apr 09 PHP
ThinkPHP登录功能的实现方法
Aug 20 PHP
PHP与MYSQL中UTF8 中文排序示例代码
Oct 23 PHP
基于GD2图形库的PHP生成图片缩略图类代码分享
Feb 08 PHP
PHP格式化MYSQL返回float类型的方法
Mar 30 PHP
使用PHP免费发送定时短信的实例
Oct 24 PHP
PHP实现的数独求解问题示例
Apr 18 PHP
使用Zttp简化Guzzle 调用
Jul 02 PHP
Laravel框架实现利用监听器进行sql语句记录功能
Jun 06 PHP
php微信公众号开发之图片回复
Oct 20 PHP
PHP Redis扩展无法加载的问题解决方法
Aug 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
PHP屏蔽蜘蛛访问代码及常用搜索引擎的HTTP_USER_AGENT
2013/03/06 PHP
解决thinkPHP 5 nginx 部署时,只跳转首页的问题
2019/10/16 PHP
prototype Element学习笔记(篇一)
2008/10/26 Javascript
修改js Calendar日历控件 兼容IE9/谷歌/火狐
2013/01/04 Javascript
引入JS文件IE6报语法错误或缺少对象问题的解决方法
2014/01/09 Javascript
指定区域的图片自动按比例缩小的js代码(防止页面被图片撑破)
2014/02/21 Javascript
js获得当前时区夏令时发生和终止的时间代码
2014/02/23 Javascript
Egret引擎开发指南之运行项目
2014/09/03 Javascript
JS模拟并美化的表单控件完整实例
2015/08/19 Javascript
JavaScript设计模式经典之命令模式
2016/02/24 Javascript
webpack+vue.js快速入门教程
2016/10/12 Javascript
JS求解三元一次方程组值的方法
2017/01/03 Javascript
JavaScript使用readAsDataUrl方法预览图片
2017/05/10 Javascript
使用vs code开发Nodejs程序的使用方法
2017/09/21 NodeJs
element el-input directive数字进行控制
2018/10/11 Javascript
详解vue中router-link标签所必备了解的属性
2019/04/15 Javascript
Vue 列表上下过渡效果的实例代码
2019/06/25 Javascript
利用Angular7开发一个Radio组件的全过程
2019/07/11 Javascript
vue+导航锚点联动-滚动监听和点击平滑滚动跳转实例
2019/11/13 Javascript
使用Python从零开始撸一个区块链
2018/03/14 Python
运用PyTorch动手搭建一个共享单车预测器
2019/08/06 Python
python爬虫模拟浏览器的两种方法实例分析
2019/12/09 Python
关于win10在tensorflow的安装及在pycharm中运行步骤详解
2020/03/16 Python
django 外键创建注意事项说明
2020/05/20 Python
python实现从ftp上下载文件的实例方法
2020/07/19 Python
Numpy实现卷积神经网络(CNN)的示例
2020/10/09 Python
python中str内置函数用法总结
2020/12/27 Python
浅析pandas随机排列与随机抽样
2021/01/22 Python
大学生村官承诺书
2014/03/28 职场文书
培训研修方案
2014/06/06 职场文书
森林防火宣传标语
2014/06/27 职场文书
2014年预备党员端正入党动机思想汇报
2014/09/13 职场文书
寻衅滋事罪辩护词
2015/05/21 职场文书
迎新晚会主持词开场白
2015/05/28 职场文书
新郎父母婚礼答谢词
2015/09/29 职场文书
2016党员发展对象培训心得体会
2016/01/08 职场文书