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 XML error parsing SOAP payload on line 1
Jun 17 PHP
php操作mysqli(示例代码)
Oct 28 PHP
PHP捕获Fatal error错误的方法
Jun 11 PHP
PHPMailer发送HTML内容、带附件的邮件实例
Jul 01 PHP
浅析PHP程序设计中的MVC编程思想
Jul 28 PHP
php中隐形字符65279(utf-8的BOM头)问题
Aug 16 PHP
PHP大转盘中奖概率算法实例
Oct 21 PHP
PHP处理大量表单字段的便捷方法
Feb 07 PHP
Smarty环境配置与使用入门教程
May 11 PHP
php实现的debug log日志操作类实例
Jul 12 PHP
php中namespace及use用法分析
Dec 06 PHP
PHP实现将多个文件压缩成zip格式并下载到本地的方法示例
May 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
PHP随机数生成代码与使用实例分析
2011/04/08 PHP
php实现的Timer页面运行时间监测类
2014/09/24 PHP
浅析php工厂模式
2014/11/25 PHP
ThinkPHP函数详解之M方法和R方法
2015/09/10 PHP
使用正则替换变量
2007/05/05 Javascript
javascript 嵌套的函数(作用域链)
2010/03/15 Javascript
onmouseover和onmouseout的一些问题思考
2013/08/14 Javascript
JavaScript整除运算函数ceil和floor的区别分析
2015/04/14 Javascript
javascript处理a标签超链接默认事件的方法
2015/06/29 Javascript
使用jquery给新生的th绑定hover事件的实例
2017/02/10 Javascript
JavaScript观察者模式(publish/subscribe)原理与实现方法
2017/03/30 Javascript
基于nodejs实现微信支付功能
2017/12/20 NodeJs
Vuejs开发环境搭建及热更新【推荐】
2018/09/07 Javascript
js隐式转换的知识实例讲解
2018/09/28 Javascript
如何阻止小程序遮罩层下方图层滚动
2019/09/05 Javascript
小程序实现长按保存图片的方法
2019/12/31 Javascript
JavaScript常用工具函数大全
2020/05/06 Javascript
对vuex中store和$store的区别说明
2020/07/24 Javascript
python中的文件打开与关闭操作命令介绍
2018/04/26 Python
Python模块的加载讲解
2019/01/15 Python
python求最大值,不使用内置函数的实现方法
2019/07/09 Python
tensorflow 2.1.0 安装与实战教程(CASIA FACE v5)
2020/06/30 Python
使用CSS3编写类似iOS中的复选框及带开关的按钮
2016/04/11 HTML / CSS
美国宠物用品网站:Value Pet Supplies
2018/03/17 全球购物
介绍一下.NET构架下remoting和webservice
2014/05/08 面试题
医院辞职信范文
2014/01/17 职场文书
求职信范文怎么写
2014/01/29 职场文书
企业新年寄语
2014/04/04 职场文书
大学生就业策划书范文
2014/04/04 职场文书
大学生优秀班干部事迹材料
2014/05/26 职场文书
学习十八大标语
2014/10/09 职场文书
物业保安辞职信
2015/05/12 职场文书
2016年师德学习心得体会
2016/01/12 职场文书
创业计划书之个人工作室
2019/08/22 职场文书
为什么mysql字段要使用NOT NULL
2021/05/13 MySQL
java固定大小队列的几种实现方式详解
2021/07/15 Java/Android