page contents

swoole 第5次课-依葫芦画瓢:加速tp6,实现swoole聊天室、队列消息和服务通信

加速tp6,swoole聊天室,swoole队列消息,swoole服务通信

1.加速 tp6

tp6 public公共文件夹下建立加速文件:class\05\tp6\public\swoolejhy.php

<?php

namespace think;

require __DIR__ . '/../vendor/autoload.php';

// 执行HTTP应用并响应
$httpTp = (new App())->http;

//高性能HTTP服务器
// 1. 创建swoole的服务
$http = new \Swoole\Http\Server('0.0.0.0',9502);

$http->on('request',function($request_swoole,$reponse_swoole) use ($httpTp){
// var_dump($_GET);
//关于全局变量$_GET/$_POST/等等问题,swoole中进行了修改处理,原全局变量失效,如若使用,可重新赋值获取。如下
// var_dump($request_swoole->get);
// $_GET = $request_swoole->get;
// var_dump($_GET);
$response = $httpTp->run();
//增加响应编码,便于前台输出正确格式
$reponse_swoole->header("Content-Type", "text/html;charset=utf-8");
//下面响应是不行的,$response->send()中本质是echo输出的,在swoole中这个echo输出是供控制台输出的,不是供浏览器物输出的。
//$reponse_swoole->end($response->send());
//上面改正为如下
$reponse_swoole->end($response->getData());
$httpTp->end($response);
});

$http->start();

运行方法

打开 Xshell,进入对应目录下,运行swoolejhy.php

attachments-2020-12-1ps70q1c5fc8d702976d7.png浏览器中:http://192.168.204.168:9502/,运行结果为

attachments-2020-12-bKc5EaFb5fc8d74e93634.jpg而不用swoole加速,打开http://192.168.204.168/class/05/tp6/public/index.php,运行结果为:

attachments-2020-12-tUB9ApQW5fc8d7a054876.png


   对比,发现快的很多,说明加速快了很多。

   注意上面代码中的两个问题

   11)swoole响应的内容 $reponse_swoole->end($response->send());要改为$reponse_swoole->end($response->getData());

因为在swoole中这个echo输出是供控制台输出的,不是供浏览器物输出的,此时,用上面的运行方法,浏览器里无内容,但xshell里输出了。

$response->send()最终的响应是echo,见下

send()

public function send(): void
{
// 处理输出数据
$data = $this->getContent();

if (!headers_sent() && !empty($this->header)) {
// 发送状态码
http_response_code($this->code);
// 发送头部信息
foreach ($this->header as $name => $val) {
header($name . (!is_null($val) ? ':' . $val : ''));
}
}
if ($this->cookie) {
$this->cookie->save();
}

$this->sendData($data); //调用

if (function_exists('fastcgi_finish_request')) {
// 提高页面响应
fastcgi_finish_request();
}
}

 而sendData()

protected function sendData(string $data): void
{
echo $data;
}

$response->getData()最终是return返回,见下

public function getData()
{
return $this->data;
}

 

12)关于php全局变量的问题,swoole中进行了修改处理,原全局变量失效,这点手册中已有说明


全局变量

协程使得原有的异步逻辑同步化,但是在协程的切换是隐式发生的,所以在协程切换的前后不能保证全局变量以及 static 变量的一致性。

在 PHP-FPM 下可以通过全局变量获取到请求的参数,服务器的参数等,在 Swoole 内,无法 通过 $_GET/$_POST/$_REQUEST/$_SESSION/$_COOKIE/$_SERVER 等 $_开头的变量获取到任何属性参数。

可以使用 context 用协程 id 做隔离,实现全局变量的隔离。


其实这点,在源码中也有体现:tp6\vendor\topthink\framework\src\think\Request.php的__make()方法中

$request->get     = $_GET;
$request->post = $_POST ?: $inputData;
$request->put = $inputData;
$request->request = $_REQUEST;
$request->cookie = $_COOKIE;
$request->file = $_FILES ?? [];

关于解决方法,如上代码重新赋值回来就行,但一般主流框架往往不需要这样,直接用对应的框架加速组件就行了。

// var_dump($_GET);//打印为空
//关于全局变量$_GET/$_POST/等等问题,swoole中进行了修改处理,原全局变量失效,如若使用,可重新赋值获取。如下
var_dump($request_swoole->get); //框架中的获取方式
$_GET = $request_swoole->get;//重新赋值回来
var_dump($_GET);//可正常应用了

 其他 ,用了加速程序里面不能用exit,再就是加速的框架,必须是ioc

再就是favicon.ico图标两次访问的问题,在onRequest方法中顶部,直接找到屏蔽掉就行了

if($request_swoole->server['path_info']=='/favicon.ico'||$request_swoole->server['request_uri']=='/favicon.ico'){$reponse_swoole->end();

return;}

2.用swoole实现简单聊天室

  功能上非常简单,客户端发个信息给服务端,服务端回一个消息,仅此而矣,仅作演示用

  服务端,与之前第2次课常用功能上手的22)WebSocket-Server 服务一样的,只是更改为面向对象的方式,具体如下

  class\05\imi\websocket.php

  <?php

/*
$server = new Swoole\Websocket\Server("0.0.0.0", 9502);
$server->on('open', function($server, $req) {
echo "connection open: {$req->fd}\n";
});
$server->on('message', function($server, $frame) {
echo "received message: {$frame->data}\n";
$server->push($frame->fd, json_encode(["hello", "world"]));
});
$server->on('close', function($server, $fd) {
echo "connection close: {$fd}\n";
});
$server->start();*/

class WebsocketServer{
private $server;
private $host='0.0.0.0';
private $port='9500';
public function __construct()
{
$this->server = new Swoole\WebSocket\Server($this->host,$this->port);
echo swoole_get_local_ip()['ens33'].':'.$this->port."\n";
$this->onInit();
}
public function open($server, $req){
echo "connection open: {$req->fd}\n";
}
public function message($server, $frame){
echo "received message: {$frame->data}\n";
$server->push($frame->fd, json_encode(["msg" => "hello"]));
}
public function close($server, $fd){
echo "connection close: {$fd}\n";
}
//注册事件函数
public function onInit(){
// [$this, 'open'] 把对象方法转为闭包参数传递
$this->server->on("open",[$this,"open"]);
$this->server->on("message",[$this,"message"]);
$this->server->on("close",[$this,"close"]);
}
public function start(){
$this->server->start();
}
}
//启动服务
(new WebsocketServer())->start();

 客户端:class\05\imi\client\index.html

 <!DOCTYPE html>

<html>
<head>
<meta charset="UTF-8">
<title>HTML5模拟微信聊天界面</title>
<link rel="stylesheet" href="css/style.css">
<script src="js/jquery.min.js" charset="utf-8"></script>
<script>
window.onload = function(){
var arrIcon = ['img/1.jpg','img/2.jpg'];
var num = 0; //控制头像改变
var iNow = -1; //用来累加改变左右浮动
var icon = document.getElementById('user_face_icon').getElementsByTagName('img');
var btn = document.getElementById('btn');
var text = document.getElementById('text');
var content = document.getElementsByTagName('ul')[0];
var img = content.getElementsByTagName('img');
var span = content.getElementsByTagName('span');
btn.onclick = function(){
if(text.value ==''){
alert('不能发送空消息');
}else {
content.innerHTML += '<li><img src="'+arrIcon[0]+'"><span>'+text.value+'</span></li>';
iNow++;
if(num==0){
img[iNow].className += 'imgright';
span[iNow].className += 'spanright';
} else {
img[iNow].className += 'imgleft';
span[iNow].className += 'spanleft';
}

webSocket.send(`{"method":"chat","msg":"${text.value}"}`);
text.value = '';
// 内容过多时,将滚动条放置到最底端
content.scrollTop=content.scrollHeight;
}
}
var webSocket = new WebSocket('ws://192.168.204.168:9500');

webSocket.onerror = function(event) {
console.log("error" + event.data);
};

// 打开websocket
webSocket.onopen = function(event) {
console.log("open:" + sockState());
};

//监听消息
webSocket.onmessage = function(event) {
console.log("onMessage");
var data = eval('(' + event.data + ')');

content.innerHTML += '<li><img src="'+arrIcon[1]+'"><span>'+data.msg+'</span></li>';
iNow++;
img[iNow].className += 'imgleft';
span[iNow].className += 'imgleft';
text.value = '';
// 内容过多时,将滚动条放置到最底端
content.scrollTop=content.scrollHeight;
};

webSocket.onclose = function(event) {
document.getElementById("message").innerHTML = "<p>close</p>";
console.log("close:" + sockState());
webSocket.close();
}

function sockState() {
var status = ['未连接', '连接成功,可通讯', '正在关闭', '连接已关闭或无法打开'];
return status[webSocket.readyState];
}
}
</script>
</head>
<body>
<div id="container">
<div class="header">
<span style="float: left;">微信聊天界面</span>
<span style="float: right;">14:21</span>
</div>
<ul class="content">
</ul>
<div class="footer">
<div id="user_face_icon">
<img src="img/1.jpg" alt="">
</div>
<input id="text" type="text" placeholder="说点什么吧...">
<span id="btn">发送</span>
</div>
</div>
</body>
</html>

 运行方法,打开 xshell,进入对应目录,运行服务端文件,具体如下(含客户端交互的输出信息)

attachments-2020-12-dTfVXnd75fca2227cd50b.jpg打开浏览器,http://192.168.204.168/class/05/imi/client/index.html或file:///D:/phpstudy_pro/WWW/swoole_2006/class/05/imi/client/index.html,打开控制台,发送信息,具体如下,对应观看xshell信息,如上

attachments-2020-12-v4Z7AP7l5fca223ede4d5.png

 扩展,实现人与人的聊天沟通(上面的仅是人机沟通客即客户端--服务端)的通讯分析

方式一 私聊

attachments-2020-12-E1tmvEyu5fca243981466.png

方式二 广播

attachments-2020-12-57ForFQK5fca24716fe4b.png

 扩展,实现人与人的聊天沟通(上面的仅是人机沟通客即客户端--服务端)的思路


attachments-2020-12-IA4TsgtY5fca23125062b.png

补充:广播的$connections

$connections

TCP 连接迭代器,可以使用 foreach 遍历服务器当前所有的连接,此属性的功能与 Server->getClientList 是一致的,但是更加友好。

遍历的元素为单个连接的 fd。

Swoole\Server->connectionsCopy to clipboardErrorCopied

$connections 属性是一个迭代器对象,不是 PHP 数组,所以不能用 var_dump 或者数组下标来访问,只能通过 foreach 进行遍历操作


字符限制,未完,见swoole 第5次课-依葫芦画瓢:加速tp6,实现swoole聊天室、队列消息和服务通信2

  • 发表于 2020-12-03 20:13
  • 阅读 ( 1023 )

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
吉洪叶
吉洪叶

21 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 1478 文章
  3. Pack 1135 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章