在 Laravel 中集成 Swoole 实现 WebSocket 服务器
创建 WebSocketService 类 关于 LaravelS 扩展包我们之前在介绍基于 Swoole 实现 HTTP 服务器的时候已经提到过了,这里不再赘述,若未安装可以参考LaravelS基于Swoole实现高性能 HTTP 服务器教程进行安装和配置,要基于该扩展包实现 WebSocket 服务器,首先首先需要创建一个实现了 Hhxsv5\LaravelS\Swoole\WebSocketHandlerInterface 接口的 WebSocketService 类:
<?php
namespace App\Services;
use Hhxsv5\LaravelS\Swoole\WebSocketHandlerInterface;
use Illuminate\Support\Facades\Log;
use Swoole\Http\Request;
use Swoole\WebSocket\Frame;
use Swoole\WebSocket\Server;
class WebSocketService implements WebSocketHandlerInterface
{
public function __construct()
{
}
// 连接建立时触发
public function onOpen(Server $server, Request $request)
{
// 在触发 WebSocket 连接建立事件之前,Laravel 应用初始化的生命周期已经结束,你可以在这里获取 Laravel 请求和会话数据
// 调用 push 方法向客户端推送数据,fd 是客户端连接标识字段
Log::info('WebSocket 连接建立');
$server->push($request->fd, 'Welcome to WebSocket Server built on LaravelS');
}
// 收到消息时触发
public function onMessage(Server $server, Frame $frame)
{
// 调用 push 方法向客户端推送数据
//$frame->fd fd绑定客户端传过来的标识uid $frame->data data 发送的内容
$server->push($frame->fd, 'This is a message sent from WebSocket Server at ' . date('Y-m-d H:i:s'));
}
// 关闭连接时触发
public function onClose(Server $server, $fd, $reactorId)
{
Log::info('WebSocket 连接关闭');
}
}
在这个 WebSocket 服务器类中,需要实现接口中声明的方法,其实就是 WebSocket 通信事件的回调函数,和上篇教程(基于 Swoole 实现简单的 WebSocket 服务器及客户端
)介绍的原生实现基本一致,只是通过类进行了封装而已。
修改配置文件 接下来,打开配置文件 config/laravels.php,启用 WebSocket 通信并将刚刚创建的服务器类配置到对应的配置项:
'websocket' => [
'enable' => true,
'handler' => \App\Services\WebSocketService::class,
],
我们还可以在 swoole 配置项中配置 WebSocket 长连接的强制关闭逻辑:
'swoole' => [
...
// 每隔 60s 检测一次所有连接,如果某个连接在 600s 内都没有发送任何数据,则关闭该连接
'heartbeat_idle_time' => 600,
'heartbeat_check_interval' => 60,
...
],
此外,记得在对应 Laravel 项目根目录下 .env 环境配置文件中设置如下配置项:
LARAVELS_LISTEN_IP=workspace // 这里的 IP 需要和 nginx upstream 中配置的监听 IP 保持一致
LARAVELS_DAEMONIZE=true
演示基于 Laravel 的 WebSocket 通信 在 Laravel 项目根目下启动 Swoole 服务器:
php bin/laravels start
启动成功后,就可以看到基于 Swoole 的 HTTP 服务器和 WebSocket 服务器信息了:
然后,我们基于上一篇教程(基于 Swoole 实现简单的 WebSocket 服务器及客户端
)创建的 WebSocket 客户端,将其中的 WebSocket Server IP 和端口修改如下:
// 初始化 WebSocket 客户端套接字并建立与服务器的连接
var socket = new WebSocket("ws://todo-s.test/ws");
点击「确定」,即可开始建立与 Laravel WebSocket 服务器的通信: 在开发者工具栏 Network->WS 标签页同样可以看到基于 HTTP 协议的 Websocket 通信握手和建立过程: 如果我们在输入框中发送消息,即可触发 WebSocket 服务器推送消息给客户端: 同时,在 storage/logs 目录下也可以看到通信连接建立与断开的日志信息:
[2019-05-22 13:55:02] local.INFO: WebSocket 连接建立
[2019-05-22 13:55:10] local.INFO: WebSocket 连接关闭
[2019-05-22 13:56:25] local.INFO: WebSocket 连接建立
[2019-05-22 13:57:25] local.INFO: WebSocket 连接关闭
[2019-05-22 14:01:18] local.INFO: WebSocket 连接建立
[2019-05-22 14:02:20] local.INFO: WebSocket 连接关闭
简易聊天室:http://admin.chencong.fun 打开两个窗口 进行演示: 上代码
<?php
namespace App\Services;
use Hhxsv5\LaravelS\Swoole\WebSocketHandlerInterface;
use Illuminate\Support\Facades\Log;
use Swoole\Http\Request;
use Swoole\WebSocket\Frame;
use Swoole\WebSocket\Server;
class WebSocketService implements WebSocketHandlerInterface
{
public function __construct()
{
Log::info('进入初始放法');
}
// 连接建立时触发
public function onOpen(Server $server, Request $request)
{
// 在触发 WebSocket 连接建立事件之前,Laravel 应用初始化的生命周期已经结束,你可以在这里获取 Laravel 请求和会话数据
// 调用 push 方法向客户端推送数据,fd 是客户端连接标识字段
Log::info("标示id:".$request->fd.'WebSocket 连接建立');
$server->push($request->fd, 'WebSocket 连接建立'.$request->fd);
}
// 收到消息时触发
public function onMessage(Server $server, Frame $frame)
{
/*$frame->data 传输时可以传json字符串 */
$data=json_decode($frame->data,true);
Log::info("标示id:".$frame->fd." 用户:".$data['username']." 发送消息:".$data['msg']);
/* $server->connections所有的用户id都存放在里面 */
foreach ($server->connections as $fd ){
if($fd==$frame->fd){
// 调用 push 方法向客户端推送数据
$server->push($fd, date('Y-m-d H:i:s').'我('.$data['username'].' 标示id:'.$frame->fd.')发送的消息:'.$data['msg'] );
}else{
$server->push($fd, date('Y-m-d H:i:s').'对方('.$data['username'].' 标示id:'.$frame->fd.')发送的消息:'.$data['msg']);
}
}
}
// 关闭连接时触发
public function onClose(Server $server, $fd, $reactorId)
{
Log::info("标示id:".$fd.'WebSocket 连接关闭'.$reactorId);
// $server->push($fd, "我(标示id:".$sfd.")WebSocket 连接关闭 reactorId:".$reactorId);
}
}
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Chat Client</title>
</head>
<body>
<script>
window.onload = function () {
var nick = prompt("输入用户名");
var input = document.getElementById("input");
input.focus();
// 初始化客户端套接字并建立连接
// var socket = new WebSocket("ws://admin.chencong.fun//:5200");
var socket = new WebSocket("ws://admin.chencong.fun/ws");
// var socket = new WebSocket("ws://admin.chencong.fun/Swoole");
// 连接建立时触发
socket.onopen = function (event) {
console.log("Connection open ...");
}
// 接收到服务端推送时执行
socket.onmessage = function (event) {
var msg = event.data;
var node = document.createTextNode(msg);
var div = document.createElement("div");
div.appendChild(node);
document.body.insertBefore(div, input);
input.scrollIntoView();
};
// 连接关闭时触发
socket.onclose = function (event) {
console.log("Connection closed ...");
}
input.onchange = function () {
var data={
'username':nick,
'msg':input.value
// 'pid':pid
};
// var msg = nick + ": " + input.value;
var msg=JSON.stringify(data);
// 将输入框变更信息通过 send 方法发送到服务器
socket.send(msg);
input.value = "";
};
}
</script>
<input id="input" style="width: 100%;">
</body>
</html>
猜你喜欢
基于 Swoole 实现简单的 WebSocket 服务器及客户端
阅读 1199基于 Swoole 实现简单的 WebSocket 服务器及客户端
Laravel验证码
阅读 620Composer生成Laravel验证码
Git使用
阅读 591Git基本配置/服务器搭建仓库
PHP定时任务
阅读 1597PHP框架Laravel定时任务的实现
Swoole 实现长连接
阅读 2317Swoole 实现长连接,心跳
黑客、后门
阅读 1425留下的网站后门,可以作什么?
Layui富文本视频等多功能
阅读 620Layui富文本多功能添加
Laravel邮箱推送
阅读 1789Laravel发送邮件