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 相关文章推荐
wordpress之wp-settings.php
Aug 17 PHP
php Undefined index和Undefined variable的解决方法
Mar 27 PHP
php empty函数 使用说明
Aug 10 PHP
php引用计数器进行垃圾收集机制介绍
Sep 19 PHP
PHP生成Gif图片验证码
Oct 27 PHP
php生成txt文件标题及内容的方法
Jan 16 PHP
PHP Curl出现403错误的解决办法
May 29 PHP
php单例模式示例分享
Feb 12 PHP
php使用curl简单抓取远程url的方法
Mar 13 PHP
PHP面向对象程序设计之对象生成方法详解
Dec 02 PHP
PHP培训要多少钱
Jun 06 PHP
PHP实现可精确验证身份证号码的工具类示例
May 31 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 多线程上下文中安全写文件实现代码
2009/12/28 PHP
基于PHP字符串的比较函数strcmp()与strcasecmp()的使用详解
2013/05/15 PHP
php遍历目录与文件夹的多种方法详解
2013/11/14 PHP
PHP递归复制、移动目录的自定义函数分享
2014/11/18 PHP
php的mssql数据库连接类实例
2014/11/28 PHP
详解PHP中mb_strpos的使用
2018/02/04 PHP
jQuery实现瀑布流布局
2014/12/12 Javascript
JS动态修改iframe高度和宽度的方法
2015/04/01 Javascript
Jquery使用val方法读写value值
2015/05/18 Javascript
js 文字超出长度用省略号代替,鼠标悬停并以悬浮框显示实例
2016/12/06 Javascript
微信小程序商品到详情的实现
2017/06/27 Javascript
基于Vue实现图片在指定区域内移动的思路详解
2018/11/11 Javascript
详解Vue+ElementUI从零开始搭建自己的网站(一、环境搭建)
2019/04/30 Javascript
微信小程序云开发如何使用npm安装依赖
2019/05/18 Javascript
小程序实现背景音乐播放和暂停
2020/06/19 Javascript
在vue中实现echarts随窗体变化
2020/07/27 Javascript
详谈Numpy中数组重塑、合并与拆分方法
2018/04/17 Python
Python3实现购物车功能
2018/04/18 Python
python中的变量如何开辟内存
2018/06/26 Python
Python开发的十个小贴士和技巧及长常犯错误
2018/09/27 Python
解决django无法访问本地static文件(js,css,img)网页里js,cs都加载不了
2020/04/07 Python
解决Keras TensorFlow 混编中 trainable=False设置无效问题
2020/06/28 Python
python中的错误如何查看
2020/07/08 Python
css3模拟jq点击事件的实例代码
2017/07/06 HTML / CSS
shell程序如何生命变量?shell变量是弱变量吗?
2014/11/10 面试题
水产养殖学应届生求职信
2013/09/29 职场文书
企业内部培训方案
2014/02/04 职场文书
中文教师求职信
2014/02/22 职场文书
幼儿园优秀班主任事迹材料
2014/05/14 职场文书
奉献家乡演讲稿
2014/09/13 职场文书
员工培训协议书
2014/09/15 职场文书
2014年设备管理工作总结
2014/11/26 职场文书
借条如何写
2015/05/26 职场文书
2016教师学习教育法心得体会
2016/01/19 职场文书
Redis缓存-序列化对象存储乱码问题的解决
2021/06/21 Redis
使用refresh_token实现无感刷新页面
2022/04/26 Javascript