Swoole 是一个使用 C++ 语言编写的基于异步事件驱动和协程的并行网络通信引擎,为 PHP 提供协程、高性能网络编程支持。提供了多种通信协议的网络服务器和客户端模块,可以方便快速的实现 TCP/UDP服务、高性能Web、WebSocket服务、物联网、实时通讯、游戏、微服务等,使 PHP 不再局限于传统的 Web 领域。
- window搭建环境:教程
- php基于http的,对于实时响应的场景比较乏力,swoole就是解决这样应用场景的。(比如网络游戏或者推送服务一般都需要与用户长期保持一个tcp连接以便实时响应和推送信息。)
- swoole让php自身建立一个服务,不需要nginx之类的代理,直接监听端口实现通信。
HTTP服务器
// ============================================= //
// HTTP服务器
// 请求方式:浏览器请求http://127.0.0.1:9501
// ============================================= //
$http = new Swoole\Http\Server("127.0.0.1", 9501);
$http->on("start", function ($server) {
echo "Swoole http server is started at http://127.0.0.1:9501\n";
});
$http->on("request", function ($request, $response) {
// Chrome 请求两次问题
if ($request->server['path_info'] == '/favicon.ico' || $request->server['request_uri'] == '/favicon.ico') {
$response->end();
return;
}
// var_dump($request->server);
$response->header("Content-Type", "text/plain");
$response->end("Hello World\n");
echo "有人请求\n";
});
$http->start();
WebSocket 服务器
// ============================================= //
// WebSocket 服务器
// 请求方式:js请求
// ============================================= //
//创建WebSocket Server对象,监听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->server);
$ws->push($request->fd, "Hello World\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 close\n";
});
$ws->start();
// js
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);
};
实例:简单聊天室github
<?php
class Chat
{
public static $instance;
public $server;
public $file = __DIR__ . '/chatLog.txt';
public function __construct()
{
//创建WebSocket Server对象,监听0.0.0.0:9502端口
$this->server = new Swoole\WebSocket\Server('0.0.0.0', 9502);
//监听WebSocket连接打开事件
$this->server->on('open', function (Swoole\WebSocket\Server $server, $request) {
echo "server:{$request->fd} into chat\n";
// 用户列表
$userList = file_exists($this->file) ? array_filter(explode(",", file_get_contents($this->file))) : [];
// 用户加入聊天室
array_push($userList, $request->fd);
file_put_contents($this->file, join(',', $userList), LOCK_EX);
});
//监听WebSocket消息事件
$this->server->on('message', function (Swoole\WebSocket\Server $server, $frame) {
echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
// 获取聊天用户
$userList = array_values(array_filter(explode(",", file_get_contents($this->file))));
// 组装消息数据
$msg = json_encode([
'fd' => $frame->fd, // 客户ID
'msg' => $frame->data, // 发送消息
'total_num' => count($userList) // 在线人数
], JSON_UNESCAPED_UNICODE);
// 发送信息
foreach ($userList as $fdId) {
$server->push($fdId, $msg);
}
});
//监听WebSocket连接关闭事件
$this->server->on('close', function (Swoole\WebSocket\Server $server, $fd) {
// 获取聊天用户
$userList = array_filter(explode(",", file_get_contents($this->file)));
$userList = array_filter(array_diff($userList, [$fd]));
// 组装消息数据
$msg = json_encode([
'fd' => $fd, // 客户ID
'msg' => '离开聊天室', // 发送消息
'total_num' => count($userList) // 在线人数
], JSON_UNESCAPED_UNICODE);
// 发送信息
foreach ($userList as $fdId) {
$server->push($fdId, $msg);
}
file_put_contents($this->file, join(',', $userList), LOCK_EX);
echo "client-{$fd} is closed\n";
});
$this->server->on('request', function ($request, $response) {
// 接收http请求从get获取message参数的值,给用户推送
// $this->server->connections 遍历所有websocket连接用户的fd,给所有用户推送
foreach ($this->server->connections as $fd) {
// 需要先判断是否是正确的websocket连接,否则有可能会push失败
if ($this->server->isEstablished($fd)) {
$this->server->push($fd, $request->get['message']);
}
}
});
$this->server->start();
}
public static function getInstance() {
if (!self::$instance) {
self::$instance = new Chat;
}
return self::$instance;
}
}
Chat::getInstance();