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 file_put_contents()功能函数(集成了fopen、fwrite、fclose)
May 24 PHP
php设计模式 Factory(工厂模式)
Jun 26 PHP
smarty 缓存控制前的页面静态化原理
Mar 15 PHP
php更新mysql后获取影响的行数发生异常解决方法
Mar 28 PHP
Laravel 5.0 发布 新版本特性详解
Feb 10 PHP
php操作(删除,提取,增加)zip文件方法详解
Mar 12 PHP
php字符串按照单词进行反转的方法
Mar 14 PHP
PHP+MySQL统计该库中每个表的记录数并按递减顺序排列的方法
Feb 15 PHP
php 解析xml 的四种方法详细介绍
Oct 26 PHP
yii2利用自带UploadedFile实现上传图片的示例
Feb 16 PHP
基于php双引号中访问数组元素报错的解决方法
Feb 01 PHP
php依赖注入知识点详解
Sep 23 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
利用discuz实现PHP大文件上传应用实例代码
2008/11/14 PHP
sphinx增量索引的一个问题
2011/06/14 PHP
PHP大转盘中奖概率算法实例
2014/10/21 PHP
phpmyadmin中禁止外网使用的方法
2014/11/04 PHP
使用PHP接受文件并获得其后缀名的方法
2015/08/05 PHP
PDO的安全处理与事物处理方法
2016/10/31 PHP
PHP反射机制原理与用法详解
2017/02/15 PHP
php写入文件不覆盖的实例讲解
2019/09/17 PHP
javascript中将Object转换为String函数代码 (json str)
2012/04/29 Javascript
基于jquery的禁用右键、文本选择功能、复制按键的实现代码
2013/08/27 Javascript
js获取触发事件元素在整个网页中的绝对坐标(示例代码)
2013/12/13 Javascript
jQuery 2.0.3 源码分析之core(一)整体架构
2014/05/27 Javascript
JavaScript实现简单Tip提示框效果
2016/04/20 Javascript
AngularJS入门教程之Scope(作用域)
2016/07/27 Javascript
JavaScript面向对象编写购物车功能
2016/08/19 Javascript
jquery 动态合并单元格的实现方法
2016/08/26 Javascript
JS树形菜单组件Bootstrap TreeView使用方法详解
2016/12/21 Javascript
jQuery实现全选、反选和不选功能
2017/08/16 jQuery
jQuery中的类名选择器(.class)用法简单示例
2018/05/14 jQuery
NodeJS有难度的面试题(能答对几个)
2019/10/09 NodeJs
详解python中的装饰器
2018/07/10 Python
解决使用pycharm提交代码时冲突之后文件丢失找回的方法
2018/08/05 Python
python实现简单登陆系统
2018/10/18 Python
Django中的ajax请求
2018/10/19 Python
通过python的matplotlib包将Tensorflow数据进行可视化的方法
2019/01/09 Python
django之使用celery-把耗时程序放到celery里面执行的方法
2019/07/12 Python
python 根据字典的键值进行排序的方法
2019/07/24 Python
解决Python3.8用pip安装turtle-0.0.2出现错误问题
2020/02/11 Python
初入社会应届生求职信
2013/11/18 职场文书
爸爸的花儿落了教学反思
2014/02/20 职场文书
2014社区三八妇女节活动方案
2014/03/30 职场文书
三年级学生期末评语
2014/12/26 职场文书
2016新年晚会开场白
2015/12/03 职场文书
使用Pytorch实现two-head(多输出)模型的操作
2021/05/28 Python
Apache Hudi 加速传统的批处理模式
2022/04/24 Servers
Java Redisson多策略注解限流
2022/09/23 Java/Android