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 相关文章推荐
oracle资料库函式库
Oct 09 PHP
PHP中Date获取时间不正确怎么办
Jun 05 PHP
PHP 递归效率分析
Nov 24 PHP
php下批量挂马和批量清马代码
Feb 27 PHP
php-fpm配置详解
Feb 12 PHP
PHP文件锁函数flock()详细介绍
Nov 18 PHP
PHP表单提交后引号前自动加反斜杠的原因及三种办法关闭php魔术引号
Sep 30 PHP
Yii清理缓存的方法
Jan 06 PHP
php图片添加文字水印实现代码
Mar 15 PHP
php实现的中文分词类完整实例
Feb 06 PHP
通过PHP实现获取访问用户IP
May 09 PHP
PHP基于openssl实现非对称加密代码实例
Jun 19 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
对text数据类型不支持代码页转换 从: 1252 到: 936
2011/04/23 PHP
ThinkPHP的Widget扩展实例
2014/06/19 PHP
Laravel框架Eloquent ORM删除数据操作示例
2019/12/03 PHP
Js切换功能的简单方法
2010/11/23 Javascript
javascript之querySelector和querySelectorAll使用说明
2011/10/09 Javascript
找出字符串中出现次数最多的字母和出现次数精简版
2012/11/07 Javascript
jquery通过a标签删除table中的一行的代码
2013/12/02 Javascript
js实现仿百度风云榜可重复多次调用的TAB切换选项卡效果
2015/08/31 Javascript
通过npm引用的vue组件使用详解
2017/03/02 Javascript
JQuery Ajax执行跨域请求数据的解决方案
2018/12/10 jQuery
Angular6新特性之Angular Material
2018/12/28 Javascript
解决vue-cli项目开发运行时内存暴涨卡死电脑问题
2019/10/29 Javascript
javascript设计模式 ? 工厂模式原理与应用实例分析
2020/04/09 Javascript
在Vue中使用CSS3实现内容无缝滚动的示例代码
2020/11/27 Vue.js
Python3实现生成随机密码的方法
2014/08/23 Python
Python判断直线和矩形是否相交的方法
2015/07/14 Python
使用Anaconda3建立虚拟独立的python2.7环境方法
2018/06/11 Python
Python机器学习库scikit-learn安装与基本使用教程
2018/06/25 Python
python使用thrift教程的方法示例
2019/03/21 Python
python随机数分布random均匀分布实例
2019/11/27 Python
Django项目使用ckeditor详解(不使用admin)
2019/12/17 Python
TensorFlow设置日志级别的几种方式小结
2020/02/04 Python
Python 实现将大图切片成小图,将小图组合成大图的例子
2020/03/14 Python
Python模块常用四种安装方式
2020/10/20 Python
Python 中如何使用 virtualenv 管理虚拟环境
2021/01/21 Python
美国新兴城市生活方式零售商:VILLA
2017/12/06 全球购物
荷兰演唱会和体育比赛订票网站:viagogo荷兰
2018/04/08 全球购物
节省高达65%的城市景点费用:Go City
2019/07/06 全球购物
几道Web/Ajax的面试题
2016/11/05 面试题
党员志愿者活动方案
2014/08/28 职场文书
团组织推优材料
2014/12/29 职场文书
承诺函格式模板
2015/01/21 职场文书
化妆品促销活动总结
2015/05/07 职场文书
小学中队委竞选稿
2015/11/20 职场文书
电力培训学习心得体会
2016/01/11 职场文书
小学教代会开幕词
2016/03/04 职场文书