TP6的websocket实现
基于tp6,简单实现WebSocket,这一篇就够了。
学习路线
php |
---|
tp6(事件机制) |
swoole的websocket实现 |
think-swoole在tp6中实现websocket |
nginx代理 |
think-swoole (案例文档) |
下面的代码,是假设在你对TP6的事件机制和swoole的websocket原生实现有所了解的基础上进行的。
-
websocket
-
websocket是出于osi模型应用层的长连接协议,允许全双工通信。更多websocket知识点—
点击这里
websocket提供了一整套用API,查看详细文档— 点击这里
swoole
- swoole是PHP一套特别框架,是一个面向生产环境的 PHP 异步网络通信引擎,使 PHP 开发人员可以编写高性能的异步并发 TCP、UDP、Unix Socket、HTTP,WebSocket 服务。详细文档— 点击这里 Nginx
- nginx代理基本知识点。nginx反向代理如何实现。
代码实现
在应用根目录下创建事件订阅类
php think make:subscribe WebSocket
WebSocket.php
<?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 WebSocket
{
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 , 'something');// 发送给客户端
}
// 监听客户端发送消息
public function onMessage(Server $server,Frame $frame)
{
$fd = $frame->fd; // 为当前连接唯一值
$msg = json_decode($frame->data , true) ;// 获取cli上传的消息,json格式
$this->server->push($fd , $msg);// 发送给客户端
}
//onClose触发的事件
public function onClose()
{
// 一般做一些资源释放的动作
}
}
修改app/config/swoole.php配置文件,没有的话就去vender扩展里面找think-swoole的扩展文件复制出来
<?php
use think\swoole\websocket\socketio\Handler;
return [
'server' => [
'host' => env('SWOOLE_HOST', '127.0.0.1'), // 监听地址
'port' => env('SWOOLE_PORT', 9000), // 监听端口
'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,// 启动websocket
'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),
'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,
],
//自定义连接池
],
'coroutine' => [
'enable' => true,
'flags' => SWOOLE_HOOK_ALL,
],
'tables' => [],
//每个worker里需要预加载以共用的实例
'concretes' => [],
//重置器
'resetters' => [],
//每次请求前需要清空的实例
'instances' => [],
//每次请求前需要重新执行的服务
'services' => [],
];
在根目录下执行
php think swoole启动监听
如果启动失败,根据提示信息修改
如果前端连接失败,一般是被nginx或防火墙拦截了。
前端html测试文件
<!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>websocket</title>
</head>
<body>
<input id="text" value="">
<input type="submit" value="send" onclick="start()">
<input type="submit" value="close" onclick="close()">
<div id="msg"></div>
<script>
/**
*0:未连接
*1:连接成功,可通讯
*2:正在关闭
*3:连接已关闭或无法打开
*/
//创建一个webSocket 实例
var webSocket = new WebSocket("ws://127.0.0.1:9000");
webSocket.onerror = function (event){
onError(event);
};
// 打开websocket
webSocket.onopen = function (event){
onOpen(event);
};
//监听消息
webSocket.onmessage = function (event){
onMessage(event);
};
webSocket.onclose = function (event){
onClose(event);
}
//关闭监听websocket
function onError(event){
document.getElementById("msg").innerHTML = "<p>close</p>";
console.log("error"+event.data);
};
function onOpen(event){
console.log("open:"+sockState());
document.getElementById("msg").innerHTML = "<p>Connect to Service</p>";
};
function onMessage(event){
console.log("onMessage");
document.getElementById("msg").innerHTML += "<p>response:"+event.data+"</p>"
};
function onClose(event){
document.getElementById("msg").innerHTML = "<p>close</p>";
console.log("close:"+sockState());
webSocket.close();
}
function sockState(){
var status = ['未连接','连接成功,可通讯','正在关闭','连接已关闭或无法打开'];
return status[webSocket.readyState];
}
function start(event){
console.log(webSocket);
var msg = document.getElementById('text').value;
document.getElementById('text').value = '';
console.log("send:"+sockState());
console.log("msg="+msg);
webSocket.send("msg="+msg);
document.getElementById("msg").innerHTML += "<p>request"+msg+"</p>"
};
function close(event){
webSocket.close();
}
</script>
</body>
</html>
-
服务端
- 前端