Server 可以监听多个端口,每个端口都可以设置不同的协议处理方式,例如 80 端口处理 HTTP 协议,9507 端口处理 TCP 协议。SSL/TLS 传输加密也可以只对特定的端口启用。
例如主服务器是 WebSocket 或 HTTP 协议,新监听的 TCP 端口(listen 的返回值,即 Swoole\Server\Port 对象,以下简称 port)默认会继承主 Server 的协议设置,必须单独调用 port 对象的 set 方法和 on 方法设置新的协议才会启用新协议。port 对象的 set 和 on 方法,使用方法与基类 Swoole\Server 完全一致。
//返回port对象
$port1 = $server->listen("127.0.0.1", 9501, SWOOLE_SOCK_TCP);
$port2 = $server->listen("127.0.0.1", 9502, SWOOLE_SOCK_UDP);
$port3 = $server->listen("127.0.0.1", 9503, SWOOLE_SOCK_TCP | SWOOLE_SSL);//port对象的调用set方法 $port1->set([ 'open_length_check' => true, 'package_length_type' => 'N', 'package_length_offset' => 0, 'package_max_length' => 800000, ]); $port3->set([ 'open_eof_split' => true, 'package_eof' => "\r\n", 'ssl_cert_file' => 'ssl.cert', 'ssl_key_file' => 'ssl.key', ]);
//设置每个port的回调函数
$port1->on('connect', function ($serv, $fd){
echo "Client:Connect.\n";
});
$port1->on('receive', function ($serv, $fd, $reactor_id, $data) {
$serv->send($fd, 'Swoole: '.$data);
$serv->close($fd);
});
$port1->on('close', function ($serv, $fd) {
echo "Client: Close.\n";
});
$port2->on('packet', function ($serv, $data, $addr) {
var_dump($data, $addr);
});Swoole\Http\Server 和 Swoole\WebSocket\Server 因为是使用继承子类实现的,无法通过调用 Swoole\Server 实例的 listen 来方法创建 HTTP 或者 WebSocket 服务器。
如服务器的主要功能为 RPC,但希望提供一个简单的 Web 管理界面。在这样的场景中,可以先创建 HTTP/WebSocket 服务器,然后再进行 listen 监听原生 TCP 的端口。
$http_server = new Swoole\Http\Server('0.0.0.0',9998);
$http_server->set(['daemonize'=> false]);
$http_server->on('request', function ($request, $response) {
$response->header("Content-Type", "text/html; charset=utf-8");
$response->end("<h1>Hello Swoole. #".rand(1000, 9999)."</h1>");
});
//多监听一个TCP端口,对外开启TCP服务,并设置TCP服务器的回调
$tcp_server = $http_server->listen('0.0.0.0', 9999, SWOOLE_SOCK_TCP);
//默认新监听的端口 9999 会继承主服务器的设置,也是 HTTP 协议
//需要调用 set 方法覆盖主服务器的设置
$tcp_server->set([]);
$tcp_server->on('receive', function ($server, $fd, $threadId, $data) {
echo $data;
});
$http_server->start();通过这样的代码,就可以建立一个对外提供 HTTP 服务,又同时对外提供 TCP 服务的 Server,更加具体的优雅代码组合则由你自己来实现。
$port1 = $server->listen("127.0.0.1", 9501, SWOOLE_SOCK_TCP);
$port1->set([
'open_websocket_protocol' => true, // 设置使得这个端口支持WebSocket协议
]);$port1 = $server->listen("127.0.0.1", 9501, SWOOLE_SOCK_TCP);
$port1->set([
'open_http_protocol' => false, // 设置这个端口关闭HTTP协议功能
]);同理还有:open_http_protocol、open_http2_protocol、open_mqtt_protocol 等参数
监听端口 port 未调用 set 方法,设置协议处理选项的监听端口,将会继承主服务器的相关配置
主服务器为 HTTP/WebSocket 服务器,如果未设置协议参数,监听的端口仍然会设置为 HTTP 或 WebSocket 协议,并且不会执行为端口设置的 onReceive 回调
主服务器为 HTTP/WebSocket 服务器,监听端口调用 set 设置配置参数,会清除主服务器的协议设定。监听端口将变为 TCP 协议。监听的端口如果希望仍然使用 HTTP/WebSocket 协议,需要在配置中增加 open_http_protocol => true 和 open_websocket_protocol => true
port 可以通过 set 设置的参数有:
socket 参数:如 backlog、open_tcp_keepalive、open_tcp_nodelay、tcp_defer_accept 等
协议相关:如 open_length_check、open_eof_check、package_length_type 等
SSL 证书相关:如 ssl_cert_file、ssl_key_file 等
具体可参考配置章节
port 未调用 on 方法,设置回调函数的监听端口,默认使用主服务器的回调函数,port 可以通过 on 方法设置的回调有:
onConnect
onClose
onReceive
onPacket
onReceive
onRequest
onMessage
onOpen
onHandshake
不同监听端口的回调函数,仍然是相同的 Worker 进程空间内执行
$server = new Swoole\WebSocket\Server("0.0.0.0", 9514, SWOOLE_BASE);
$tcp = $server->listen("0.0.0.0", 9515, SWOOLE_SOCK_TCP);
$tcp->set([]);
$server->on("open", function ($serv, $req) {
echo "new WebSocket Client, fd={$req->fd}\n";
});
$server->on("message", function ($serv, $frame) {
echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
$serv->push($frame->fd, "this is server OnMessage");
});
$tcp->on('receive', function ($server, $fd, $reactor_id, $data) {
//仅遍历 9514 端口的连接,因为是用的$server,不是$tcp
$websocket = $server->ports[0];
foreach ($websocket->connections as $_fd) {
var_dump($_fd);
if ($server->exist($_fd)) {
$server->push($_fd, "this is server onReceive");
}
}
$server->send($fd, 'receive: '.$data);
});
$server->start();