用过 workerman, 两个字”好用”,对于 swoole 最近有时间也研究研究
swoole 的 websocket 很好实现
如官网 https://wiki.swoole.com/wiki/page/479.html
ws_server.php
swoole websocket 服务推送
//创建 websocket 服务器对象,监听 0.0.0.0:9502 端口
$ws = new swoole_websocket_server("0.0.0.0", 9502);
//监听 WebSocket 连接打开事件
$ws->on('open', function ($ws, $request) {
var_dump($request->fd, $request->get, $request->server);
$ws->push($request->fd, "hello, welcome\n");
});
//监听 WebSocket 消息事件
$ws->on('message', function ($ws, $frame) {
echo "Message: {$frame->data}\n";
$ws->push($frame->fd, "server: {$frame->data}");
});
//监听 WebSocket 连接关闭事件
$ws->on('close', function ($ws, $fd) {
echo "client-{$fd} is closed\n";
});
$ws->start();
swoole websocket 服务推送
运行程序
php ws_server.php
客户端 a.html
swoole websocket 服务推送
var wsServer = 'ws://127.0.0.1:9502';
var websocket = new WebSocket(wsServer);
websocket.onopen = function (evt) {
console.log("Connected to WebSocket server.");
};
websocket.onclose = function (evt) {
console.log("Disconnected");
};
websocket.onmessage = function (evt) {
console.log('Retrieved data from server: ' + evt.data);
};
websocket.onerror = function (evt, e) {
console.log('Error occured: ' + evt.data);
};
swoole websocket 服务推送
ok 了!
现在我们看到的是客户端发送信息,服务器应答并返回数据
那我们现在要的是服务器主动发送信息
有三个办法:
1.使用 swoole 的定时器,定时发送,可通过 syc 从数据库获取数据逻辑判断后 push 发送给客户端
2.使用 swoole 中自带框架
这个方法和方法 3 原理是一样的,就是需要后台主动推送的时候,模拟一个客户端发送消息,可以是 CLI 的脚本,也可以是 php 的 CURL 请求
https://github.com/matyhtf/framework/blob/master/libs/Swoole/Client/WebSocket.php
github 下载地址: https://github.com/matyhtf/framework
swoole websocket 服务推送
<?php
define('DEBUG', 'on');
define("WEBPATH", str_replace("\\", "/", __DIR__));
require __DIR__ . '/framework-master/libs/lib_config.php';
$client = new Swoole\Client\WebSocket('127.0.0.1', 9502);
if (!$client->connect()) {
echo "connect to server failed.\n";
exit;
}
$client->send("我是 PHP-client 端,发来的消息"); # 客户端可以看到
swoole websocket 服务推送
3.设置 onRequest 回调
用过 workerman 的都知道,workerman 中就有这个获取 http 的 get,post 数据并 sendto 客户端,在这里 swoole 也可以实现
https://wiki.swoole.com/wiki/page/397.html
swoole_websocket_server 继承自 swoole_http_server
设置了 onRequest 回调,websocket 服务器也可以同时作为 http 服务器
未设置 onRequest 回调,websocket 服务器收到 http 请求后会返回http 400错误页面
如果想通过接收 http 触发所有 websocket 的推送,需要注意作用域的问题,面向过程请使用“global”对 swoole_websocket_server 进行引用,面向对象可以把 swoole_websocket_server 设置成一个成员属性
代码如下
ser.php
swoole websocket 服务推送
<?php
class MyWebsocket {
private $server;
private $fid=[];
# run()
public function toRun() {
$this->server = new swoole_websocket_server("0.0.0.0", 9502, SWOOLE_BASE, SWOOLE_SOCK_TCP); //SWOOLE_SSL 需要 ssl 才加
#监听 WebSocket 连接打开事件
$this->server->on('open', function ($server, $request) {
$this->server->push($request->fd, "hello, welcome ID:{$request->fd}\n");
$this->fid[]=$request->fd; # $request->fd fd
});
#监听 WebSocket 消息事件
$this->server->on('message', function ($server, $frame) { #$frame->data 消息内容
$msg = 'from' . $frame->fd . ":{$frame->data}\n";
foreach ($this->fid as $fd) {
$server->push($fd, $msg);
}
});
//监听 WebSocket 连接关闭事件
$this->server->on('close', function($ws, $fd) {
$fd_key = array_search($fd, $this->fid ? $this->fid : []);
$key_zero = isset($this->fid[0]) && $this->fid[0] == $fd ? TRUE : FALSE; # key=0
if ($fd_key || $key_zero) {
unset($this->fid[$fd_key]);
}
echo "client-{$fd} is closed\n";
});
#onRequest 回调 http://127.0.0.1:9502/?sendto=1,20,3&message=%E4%BD%A0%E5%A5%BD
$this->server->on('request', function ($req, $respone) {
# get 两个参数, userid "," 发送消息
$list=[];
if (isset($req->get['sendto']) && isset($req->get['message'])) {
$user = explode(',', $req->get['sendto']);
$list = array_intersect($this->fid, $user);
if (!empty($list)) {
foreach ($list as $fd) {
$this->server->push($fd, $req->get['message']);
}
}
}
$total= count($this->fid);
$sendSum= count($list);
$respone->end("Current fid:{$respone->fd}, OnLine:{$total}, Send:{$sendSum}");
});
$this->server->start();
}
}
$app = new MyWebsocket();
$app->toRun();
swoole websocket 服务推送
客户端 html
swoole websocket 服务推送
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="msg"></div>
<input type="text" id="text">
<input type="submit" value="发送数据" onclick="sending()">
</body>
<script>
var msg = document.getElementById("msg");
var wsServer = 'ws://127.0.0.1:9502';
//调用 websocket 对象建立连接:
//参数:ws/wss(加密)://ip:port (字符串)
var websocket = new WebSocket(wsServer);
//onopen 监听连接打开
websocket.onopen = function (evt) {
//websocket.readyState 属性:
/*
CONNECTING 0 The connection is not yet open.
OPEN 1 The connection is open and ready to communicate.
CLOSING 2 The connection is in the process of closing.
CLOSED 3 The connection is closed or couldn't be opened.
*/
console.log(websocket.readyState);
};
function sending() {
var text = document.getElementById('text').value;
document.getElementById('text').value = '';
//向服务器发送数据
websocket.send(text);
}
//监听连接关闭
websocket.onclose = function (evt) {
msg.innerHTML+="Disconnected<br>";
};
//onmessage 监听服务器数据推送
websocket.onmessage = function (evt) {
msg.innerHTML += evt.data + '<br>';
console.log('Retrieved data from server: ' + evt.data);
};
//监听连接错误信息
websocket.onerror = function (evt, e) {
console.log('Error occured: ' + evt.data);
};
</script>
</html>
swoole websocket 服务推送
复制代码
运行
php ser.php swoole websocket 服务推送
swoole websocket 服务推送swoole websocket 服务推送
swoole websocket 服务推送
阅读原文请访问