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作的文本留言本的例子(一)
Oct 09 PHP
利用php来自动调用不同服务器上的flash
Oct 09 PHP
关于PHP堆栈与列队的学习
Jun 21 PHP
PHP编程中的常见漏洞和代码实例
Aug 06 PHP
php延迟静态绑定实例分析
Feb 08 PHP
PHP中is_file()函数使用指南
May 08 PHP
php pthreads多线程的安装与使用
Jan 19 PHP
PHP类和对象相关系统函数与运算符小结
Sep 28 PHP
php简单统计中文个数的方法
Sep 30 PHP
PHP中的多种加密技术及代码示例解析
Oct 20 PHP
PHP中Cookie的使用详解(简单易懂)
Apr 28 PHP
php libevent 功能与使用方法详解
Mar 04 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
Protoss建筑一览
2020/03/14 星际争霸
不用数据库的多用户文件自由上传投票系统(1)
2006/10/09 PHP
初级的用php写的采集程序
2007/03/16 PHP
调试Javascript代码(浏览器F12及VS中debugger关键字)
2013/01/25 Javascript
动态加载jQuery的两种方法实例分析
2015/07/17 Javascript
jquery+css实现动感的图片切换效果
2015/11/25 Javascript
百度地图给map添加右键菜单(判断是否为marker)
2016/03/04 Javascript
学习Angularjs分页指令
2016/07/01 Javascript
nodejs中sleep功能实现暂停几秒的方法
2017/07/12 NodeJs
详解layui弹窗父子窗口之间传参数的方法
2018/01/16 Javascript
微信小程序实现的3d轮播图效果示例【基于swiper组件】
2018/12/11 Javascript
ES6 更易于继承的类语法的使用
2019/02/11 Javascript
javascript 原型与原型链的理解及应用实例分析
2020/02/10 Javascript
基于Vue实现微前端的示例代码
2020/04/24 Javascript
[56:57]LGD vs VP 2019DOTA2国际邀请赛淘汰赛 胜者组赛BO3 第一场 8.20.mp4
2019/08/22 DOTA
在Django中同时使用多个配置文件的方法
2015/07/22 Python
Python实现将sqlite数据库导出转成Excel(xls)表的方法
2017/07/17 Python
神经网络python源码分享
2017/12/15 Python
Python实现的生产者、消费者问题完整实例
2018/05/30 Python
使用PyQt的QLabel组件实现选定目标框功能的方法示例
2020/05/19 Python
装上这 14 个插件后,PyCharm 真的是无敌的存在
2021/01/11 Python
网购亚洲时装、美容产品和生活百货:YesStyle
2016/09/15 全球购物
美国高端婴童品牌:Hanna Andersson
2016/10/30 全球购物
德国大型和小型家用电器网上商店:Energeto
2019/05/15 全球购物
教师节商场活动方案
2014/02/13 职场文书
2014新年元旦活动策划方案
2014/02/18 职场文书
《小蝌蚪找妈妈》教学反思
2014/02/21 职场文书
学习决心书
2014/03/11 职场文书
小学一年级数学教学计划
2015/01/20 职场文书
公司年夜饭通知
2015/04/25 职场文书
2015迎新晚会开场白
2015/07/17 职场文书
财务管理制度范本
2015/08/04 职场文书
劳务派遣管理制度(样本)
2019/08/23 职场文书
selenium.webdriver中add_argument方法常用参数表
2021/04/08 Python
Python os和os.path模块详情
2022/04/02 Python
win10电脑双屏显示一个黑屏怎么办?win10电脑双屏显示一个黑屏解决方法
2022/07/15 数码科技