由于当前使用php7.2版本,默认使用composer安装swoole的时候会自动安装3.x版本。

服务器的扩展安装这里不介绍,另外windows不支持swoole,如果需要,可通过虚拟机或者docker实现

安装swoole

1
composer require topthink/think-swoole

创建事件订阅类

1
php think make:subscribe WebSocketEvent

将以下代码覆盖到WebSocketEvent.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?php
declare (strict_types = 1);

namespace app\subscribe;

use app\Request;
use Swoole\Server;
use Swoole\WebSocket\Frame;
use think\cache\driver\Redis;
use think\Container;

class WebSocketEvent
{
protected $websocket = null;
protected $server = null;

public function __construct(Server $server, \think\swoole\Websocket $websocket, Container $container)
{
$this->websocket = $websocket;//依赖注入的方式
$this->server = $server;
}

public function onConnect(Request $request){}

// 监听客户连接
public function onOpen(Request $request)
{
$fd = $this->websocket->getSender();// 获取连接标识
$this->server->push($fd , "fd:{$fd}连接");// 发送给客户端
echo "fd:{$fd}\n";
}

// 监听客户端发送消息
public function onMessage(Server $server,Frame $frame)
{
$fd = $frame->fd; // 为当前连接唯一值
$msg = $frame->data; // 获取得到的消息
// $this->server->push($fd , $msg); // 仅发送给当前连接的客户端
// 发送给所有连接的客户端
foreach($server->connections as $fd) {
$this->server->push($fd, $frame->data);
}
}

//onClose触发的事件
public function onClose()
{
// 一般做一些资源释放的动作
$fd = $this->websocket->getSender();// 获取当前连接值
echo "fd:{$fd}关闭了连接\n";
}
}

配置swoole.php

修改app/config/swoole.php配置文件,没有的话就去vender扩展里面找think-swoole的扩展文件复制出来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
<?php

use think\swoole\websocket\socketio\Handler;

return [
'server' => [
'host' => env('SWOOLE_HOST', '0.0.0.0'), // 监听地址
'port' => env('SWOOLE_PORT', 9502), // 监听端口
'mode' => SWOOLE_PROCESS, // 运行模式 默认为SWOOLE_PROCESS
'sock_type' => SWOOLE_SOCK_TCP, // sock type 默认为SWOOLE_SOCK_TCP
'options' => [
'pid_file' => runtime_path() . 'swoole.pid',
'log_file' => runtime_path() . 'swoole.log',
'daemonize' => false,
// Normally this value should be 1~4 times larger according to your cpu cores.
'reactor_num' => swoole_cpu_num(),
'worker_num' => swoole_cpu_num(),
'task_worker_num' => swoole_cpu_num(),
'enable_static_handler' => true,
'document_root' => root_path('public'),
'package_max_length' => 20 * 1024 * 1024,
'buffer_output_size' => 10 * 1024 * 1024,
'socket_buffer_size' => 128 * 1024 * 1024,
],
],
'websocket' => [
'enable' => true,
// 'handler' => Handler::class,
'ping_interval' => 25000,
'ping_timeout' => 60000,
'room' => [
'type' => 'table',
'table' => [
'room_rows' => 4096,
'room_size' => 2048,
'client_rows' => 8192,
'client_size' => 2048,
],
'redis' => [
'host' => '127.0.0.1',
'port' => 6379,
'max_active' => 3,
'max_wait_time' => 5,
],
],
'listen' => [],
'subscribe' => [
app\subscribe\WebSocketEvent::class
],
],
'rpc' => [
'server' => [
'enable' => false,
'port' => 9000,
'services' => [
],
],
'client' => [
],
],
//热更新
'hot_update' => [
// 'enable' => env('APP_DEBUG', false),
'enable' => true,
'name' => ['*.php'],
'include' => [app_path()],
'exclude' => [],
],
//连接池
'pool' => [
'db' => [
'enable' => true,
'max_active' => 3,
'max_wait_time' => 5,
],
'cache' => [
'enable' => true,
'max_active' => 3,
'max_wait_time' => 5,
],
//自定义连接池
],
//队列
'queue' => [
'enable' => false,
'workers' => [],
],
'coroutine' => [
'enable' => true,
'flags' => SWOOLE_HOOK_ALL,
],
'tables' => [],
//每个worker里需要预加载以共用的实例
'concretes' => [],
//重置器
'resetters' => [],
//每次请求前需要清空的实例
'instances' => [],
//每次请求前需要重新执行的服务
'services' => [],
];

启动监听

在根目录下执行php think swoole

在ssh连接可看到下发实例即为成功

1
2
3
Starting swoole http server...
Swoole http server started: <http://0.0.0.0:9502>
You can exit with `CTRL-C`

如果启动失败,那么可能存在防火墙拦截等问题。

前端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, user-scalable=no">
<title>swoole</title>
</head>
<body>
<input id="text" value="">
<input type="submit" value="send" onclick="start()">
<div id="msg"></div>
</body>
</html>
<script>
/**
*0:未连接
*1:连接成功,可通讯
*2:正在关闭
*3:连接已关闭或无法打开
*/
//创建一个webSocket 实例
var webSocket = new WebSocket("ws://服务器IP地址:9502");

webSocket.onerror = function (event){
document.getElementById("msg").innerHTML = "<p>服务器连接错误...</p>";
console.log("error"+event.data);
};

// 打开websocket
webSocket.onopen = function (event){
console.log("open:"+sockState());
document.getElementById("msg").innerHTML = "<p>服务器连接成功...</p>";
};

//监听消息
webSocket.onmessage = function (event){
console.log("onMessage");
console.log(event)
document.getElementById("msg").innerHTML += "<p>响应监听:"+event.data+"</p>"
};

webSocket.onclose = function (event){
document.getElementById("msg").innerHTML = "<p>服务器连接关闭...</p>";
console.log("close:"+sockState());
}

function sockState(){
console.log(webSocket.readyState)
var status = ['未连接','连接成功,可通讯','正在关闭','连接已关闭或无法打开'];
return status[webSocket.readyState];
}

function start(event){
console.log(webSocket);
var msg = document.getElementById('text').value;
document.getElementById('text').value = '';
webSocket.send(msg);
document.getElementById("msg").innerHTML += "<p>request"+msg+"</p>";
}
</script>

客户端页面信息:

1
2
3
4
服务器连接成功...
响应监听:fd:1连接
request发送的内容
响应监听:发送的内容

服务端监听信息:

1
2
3
4
5
Starting swoole http server...
Swoole http server started: <http://0.0.0.0:9502>
You can exit with `CTRL-C`
fd:1
连接信息frame:{"fd":1,"data":"\u53d1\u9001\u7684\u5185\u5bb9","opcode":1,"flags":33,"finish":true}

以上即为简单配置,更多方法操作可去官网详细了解

swoole文档:https://wiki.swoole.com/#/