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(1)
Oct 09 PHP
一个简单的php实现的MySQL数据浏览器
Mar 11 PHP
php实现mysql数据库备份类
Mar 20 PHP
php下判断数组中是否存在相同的值array_unique
Mar 25 PHP
编写php应用程序实现摘要式身份验证的方法详解
Jun 08 PHP
php中实现记住密码下次自动登录的例子
Nov 06 PHP
php随机获取金山词霸每日一句的方法
Jul 09 PHP
thinkphp表单上传文件并将文件路径保存到数据库中
Jul 28 PHP
php cli模式下获取参数的方法
May 05 PHP
Yii2选项卡的简单使用
May 26 PHP
Laravel实现定时任务的示例代码
Aug 10 PHP
discuz论坛更换域名,详细文件修改步骤
Dec 09 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通过array_merge()函数合并关联和非关联数组的方法
2015/03/18 PHP
php的mail函数发送UTF-8编码中文邮件时标题乱码的解决办法
2015/10/20 PHP
js+css使DIV始终居于屏幕中间 左下 左上 右上 右下的代码集合
2011/03/10 Javascript
jQuery代码优化 选择符篇
2011/11/01 Javascript
JavaScript中的apply()方法和call()方法使用介绍
2012/07/25 Javascript
js简单实现让文本框内容逐个字的显示出来
2013/10/22 Javascript
JS获取select-option-text_value的方法
2013/12/26 Javascript
javascript动态创建表格及添加数据实例详解
2015/05/13 Javascript
jquery插件tytabs.jquery.min.js实现渐变TAB选项卡效果
2015/08/25 Javascript
使用ionic播放轮询广告的实现方法(必看)
2017/04/24 Javascript
浅谈js中的this问题
2017/08/31 Javascript
基于Vue自定义指令实现按钮级权限控制思路详解
2018/05/23 Javascript
jQuery实现form表单序列化转换为json对象功能示例
2018/05/23 jQuery
Jquery和CSS实现选择框重置按钮功能
2018/11/08 jQuery
[01:14]DOTA2亚洲邀请赛小组赛赛前花絮
2017/03/27 DOTA
python用字典统计单词或汉字词个数示例
2014/04/22 Python
python和ruby,我选谁?
2017/09/13 Python
Django ManyToManyField 跨越中间表查询的方法
2018/12/18 Python
Python基于plotly模块实现的画图操作示例
2019/01/23 Python
pyqt5 使用label控件实时显示时间的实例
2019/06/14 Python
Python3 tkinter 实现文件读取及保存功能
2019/09/12 Python
Django自定义用户表+自定义admin后台中的字段实例
2019/11/18 Python
Python编译成.so文件进行加密后调用的实现
2019/12/23 Python
使用Python制作新型冠状病毒实时疫情图
2020/01/28 Python
Python如何存储数据到json文件
2020/03/09 Python
美国受信赖的教育产品供应商:Nest Learning
2018/06/14 全球购物
Koral官方网站:女性时尚运动服
2019/04/10 全球购物
一名毕业生的自我鉴定
2013/12/04 职场文书
应届毕业生个人求职自荐信
2014/01/06 职场文书
淘宝活动总结范文
2014/06/26 职场文书
2015年司法所工作总结
2015/04/27 职场文书
2016十一国庆节感言
2015/12/09 职场文书
公司会议开幕词
2016/03/03 职场文书
详解JAVA的控制语句
2021/11/11 Java/Android
MySQL慢查询优化解决问题
2022/03/17 MySQL
xhunter1.sys可以删除嘛? win11提示xhunter1.sys驱动不兼容解决办法
2022/09/23 数码科技