0

0

Swoole的WebSocket如何使用?WebSocket如何通信?

星降

星降

发布时间:2025-08-18 18:39:01

|

189人浏览过

|

来源于php中文网

原创

Swoole的WebSocket通过封装底层细节,使开发者只需关注open、message、close等事件处理,即可实现全双工通信,区别于HTTP的请求-响应模式,WebSocket支持服务器主动推送,适用于实时场景。

swoole的websocket如何使用?websocket如何通信?

Swoole的WebSocket用起来,其实比你想象的要直接得多,它把很多底层复杂的网络通信细节都封装好了,你主要就是关注事件处理。而WebSocket通信本身,它就是一种在单个TCP连接上进行全双工通信的协议,一旦握手成功,客户端和服务器就能双向自由发送数据,这跟传统的HTTP那种请求-响应模式完全不一样。

解决方案

要用Swoole搭建一个WebSocket服务器,核心就是监听几个关键事件。首先,你得创建一个

Swoole\WebSocket\Server
实例,指定监听的IP和端口。

on('open', function (Swoole\WebSocket\Server $server, $request) {
    echo "客户端 {$request->fd} 已连接。\n";
    $server->push($request->fd, "欢迎,你是第 {$request->fd} 位用户!");
});

// 当服务器收到WebSocket客户端发送的数据帧时
$server->on('message', function (Swoole\WebSocket\Server $server, $frame) {
    echo "收到客户端 {$frame->fd} 的消息: {$frame->data}\n";

    // 假设我们想把收到的消息原样发回给发送者
    $server->push($frame->fd, "服务器回应: " . $frame->data);

    // 如果是广播,可以遍历所有连接的fd并push
    // foreach ($server->connections as $fd) {
    //     if ($server->isEstablished($fd)) { // 检查连接是否仍然存在
    //         $server->push($fd, "广播消息: " . $frame->data);
    //     }
    // }
});

// 当WebSocket客户端连接关闭时
$server->on('close', function (Swoole\WebSocket\Server $server, $fd) {
    echo "客户端 {$fd} 已断开连接。\n";
});

// 启动服务器
$server->start();
?>

这段代码基本上涵盖了最基础的WebSocket服务器功能。

onOpen
事件在客户端连接并完成WebSocket握手时触发,你可以在这里做一些初始化工作,比如记录用户上线、发送欢迎消息。
onMessage
是核心,所有客户端发来的数据都会在这里处理,你可以根据
$frame->data
来决定如何响应,比如转发、存储或者执行某些业务逻辑。
onClose
则是在客户端断开连接时触发,可以用来清理资源或者通知其他用户。

客户端方面,用JavaScript就很方便:

// 假设你的Swoole WebSocket服务器运行在localhost:9501
const ws = new WebSocket('ws://localhost:9501');

ws.onopen = function(event) {
    console.log('WebSocket连接已建立!');
    ws.send('你好,Swoole!我是客户端。');
};

ws.onmessage = function(event) {
    console.log('收到服务器消息:', event.data);
};

ws.onclose = function(event) {
    console.log('WebSocket连接已关闭。');
};

ws.onerror = function(error) {
    console.error('WebSocket发生错误:', error);
};

// 你可以随时发送消息
// ws.send('这是另一条消息。');

这样,一个基本的Swoole WebSocket应用就跑起来了。

WebSocket和HTTP有什么本质区别

聊到WebSocket,很多人会下意识地把它和HTTP拿来比较,毕竟它们都跑在TCP上。但说实话,它们的“性格”完全不同。HTTP,你把它想象成一个“问答机器人”,你问一句,它答一句,然后连接就可能断了(或者保持短时间活跃,但下一句问答还是新的请求-响应周期)。每次问答,都得带上请求头、响应头这些“开场白”,挺啰嗦的。它的核心是“请求-响应”模型,无状态,每次通信都是独立的。

WebSocket则完全是另一种玩法,它更像是一条“专线电话”。一旦电话接通(完成握手),这条线就一直保持着,双方可以随时随地、不分先后地说话,想说多久就说多久,而且每次说话(发送数据帧)的“开场白”非常小。它是一种全双工、有状态的协议。这意味着服务器可以主动向客户端推送数据,而不需要客户端先发起请求,这在实时应用里简直是天赐之物,比如聊天室、在线游戏、股票行情推送等等。HTTP在这种场景下,就得靠轮询或者长轮询来模拟,效率和实时性都差一大截。

在Swoole中,如何实现WebSocket的身份验证和消息广播?

在Swoole里搞WebSocket的身份验证和消息广播,其实是两个比较常见的需求。

先说身份验证。通常,我们会在

onOpen
事件里进行。当一个客户端连接上来,
$request
对象里会包含一些HTTP头信息,比如
Cookie
或者自定义的
Authorization
头。你可以在这里解析这些信息,比如从Cookie里获取Session ID,然后去你的数据库或者缓存里验证这个Session是否有效,或者直接解析JWT令牌。

萤火商城
萤火商城

萤火商城V2.0,是2021年全新推出的一款轻量级、高性能、前后端分离的电商系统,支持微信小程序 + H5+ 公众号 + APP,前后端源码完全开源,看见及所得,完美支持二次开发,可学习可商用,让您快速搭建个性化独立商城。萤火商城V2.0开源版 [uni-app端]如何使用uni-app端一、导入uniapp项目 1. 首先下载HBuilderX并安装,地址:https://www.dcloud

下载
$server->on('open', function (Swoole\WebSocket\Server $server, $request) {
    // 假设客户端在连接时通过查询参数传递了token
    // ws://localhost:9501/?token=YOUR_AUTH_TOKEN
    $token = $request->get['token'] ?? ''; // 或者从 $request->header['cookie'] 中解析
    if (empty($token) || !$this->isValidToken($token)) { // 假设有个isValidToken方法验证
        echo "客户端 {$request->fd} 认证失败,关闭连接。\n";
        $server->disconnect($request->fd); // 直接断开连接
        return;
    }

    // 认证成功,将用户ID和fd关联起来,方便后续查找
    // 比如可以存在一个全局的Map或者Redis里
    $userId = $this->getUserIdFromToken($token); // 假设通过token获取用户ID
    // 假设我们有一个数组来存储fd和userId的映射
    $server->users[$request->fd] = $userId;
    $server->fdToUser[$userId] = $request->fd;

    echo "客户端 {$request->fd} (用户ID: {$userId}) 已连接。\n";
    $server->push($request->fd, "认证成功,欢迎回来!");
});

这里的关键是,一旦认证通过,你需要把

fd
(文件描述符,Swoole给每个连接分配的唯一ID)和你的业务用户ID关联起来,这样在后续需要向特定用户发送消息时,就能通过用户ID找到对应的
fd

接着是消息广播。这个就相对简单了。当你在

onMessage
事件里收到一条消息,想把它发给所有在线用户或者某个特定群组时,你可以遍历所有已建立的连接,然后使用
$server->push()
方法发送。

$server->on('message', function (Swoole\WebSocket\Server $server, $frame) {
    echo "收到客户端 {$frame->fd} 的消息: {$frame->data}\n";

    // 假设是聊天消息,我们要广播给所有在线用户
    foreach ($server->connections as $fd) {
        // 确保连接仍然存在且是WebSocket连接
        if ($server->isEstablished($fd)) {
            $server->push($fd, "用户 {$frame->fd} 说: " . $frame->data);
        }
    }

    // 如果是定向广播给特定群组,你需要维护群组和fd的映射关系
    // 比如:$server->groups['room_A'] = [fd1, fd2, ...];
    // 然后遍历room_A的fd列表进行push
});

Swoole的

$server->connections
属性是一个迭代器,包含了当前所有活跃连接的
fd
。在实际应用中,为了效率和管理方便,你可能不会直接遍历
$server->connections
,而是维护一个你自己的在线用户列表(比如存储在Redis里),这样可以更灵活地进行群发或定向发送。

遇到Swoole WebSocket连接断开或异常,该如何排查?

Swoole WebSocket连接断开或者出现异常,这可是常有的事儿,毕竟网络环境复杂,客户端行为也千奇百怪。排查起来,得有章法。

首先,最直接的线索就是Swoole的日志。Swoole服务器在启动时,可以配置日志文件路径,所有重要的事件、错误都会记录在里面。当连接断开时,

onClose
事件会被触发,但它只告诉你连接断开了,具体原因可能需要结合Swoole自身的错误日志来判断,比如是不是因为某个协程抛了未捕获的异常导致进程崩溃,或者Swoole内部的错误。

其次,要区分是客户端主动断开还是服务器被动断开

  • 客户端主动断开:比如用户关闭了浏览器标签页,或者JS代码里调用了
    ws.close()
    。这种情况下,
    onClose
    会正常触发,通常不会有异常日志。
  • 服务器被动断开:这就有多种情况了。
    1. 心跳超时:WebSocket协议本身没有内置的心跳机制,但为了维持连接活跃和检测死连接,我们通常会实现应用层的心跳。如果客户端长时间没有发送数据,服务器可以发送一个心跳包(ping),客户端收到后回复(pong)。如果服务器在规定时间内没有收到pong,就认为连接已死,会主动断开。Swoole本身没有自动心跳,需要你在
      onWorkerStart
      中设置定时器来发送ping,并在
      onMessage
      中处理pong。
    2. 网络问题:客户端网络波动、服务器网络抖动,都可能导致TCP连接中断,进而WebSocket连接断开。这种情况下,
      onClose
      会触发,但原因可能不明确,需要结合系统日志(如
      dmesg
      )或网络监控工具来判断。
    3. 服务器进程异常退出:Swoole Worker进程因为未捕获的PHP异常、内存溢出等原因崩溃,会导致该Worker上所有连接断开。这时,你应该检查PHP错误日志和Swoole的
      onError
      回调。你可以在
      onError
      里记录更详细的错误信息,帮助定位问题。
    4. 防火墙或代理:中间的网络设备(如防火墙、负载均衡器、CDN)可能会因为配置不当或超时设置,主动关闭空闲连接。确保你的WebSocket连接在这些设备上配置了合适的超时时间,或者通过心跳机制保持活跃。

调试策略:

  • 日志是第一手资料:确保Swoole的日志级别设置得当,并且有足够的磁盘空间来存储。
  • 客户端调试:浏览器的开发者工具(F12)的网络面板可以清楚地看到WebSocket的帧传输,包括发送和接收的数据,以及连接的状态变化,这对于排查客户端行为导致的问题非常有效。
  • 心跳机制:强烈建议为WebSocket连接实现心跳。这不仅能保持连接活跃,还能让你更早地发现死连接,避免资源浪费。一个简单的实现就是服务器每隔N秒发送一个ping帧,客户端收到后立即回复一个pong帧。如果服务器在M秒内没有收到pong,就认为连接已断开并关闭它。
  • 资源监控:监控Swoole进程的CPU、内存使用情况。如果发现异常飙升,可能是代码中存在死循环、内存泄漏等问题。
  • 错误处理:在你的Swoole代码中,对可能抛出异常的地方进行
    try-catch
    ,并在
    onError
    事件中记录详细的上下文信息,这对于定位复杂问题至关重要。

排查这些问题,往往需要耐心和多方面的信息整合。

相关专题

更多
php文件怎么打开
php文件怎么打开

打开php文件步骤:1、选择文本编辑器;2、在选择的文本编辑器中,创建一个新的文件,并将其保存为.php文件;3、在创建的PHP文件中,编写PHP代码;4、要在本地计算机上运行PHP文件,需要设置一个服务器环境;5、安装服务器环境后,需要将PHP文件放入服务器目录中;6、一旦将PHP文件放入服务器目录中,就可以通过浏览器来运行它。

2630

2023.09.01

php怎么取出数组的前几个元素
php怎么取出数组的前几个元素

取出php数组的前几个元素的方法有使用array_slice()函数、使用array_splice()函数、使用循环遍历、使用array_slice()函数和array_values()函数等。本专题为大家提供php数组相关的文章、下载、课程内容,供大家免费下载体验。

1630

2023.10.11

php反序列化失败怎么办
php反序列化失败怎么办

php反序列化失败的解决办法检查序列化数据。检查类定义、检查错误日志、更新PHP版本和应用安全措施等。本专题为大家提供php反序列化相关的文章、下载、课程内容,供大家免费下载体验。

1511

2023.10.11

php怎么连接mssql数据库
php怎么连接mssql数据库

连接方法:1、通过mssql_系列函数;2、通过sqlsrv_系列函数;3、通过odbc方式连接;4、通过PDO方式;5、通过COM方式连接。想了解php怎么连接mssql数据库的详细内容,可以访问下面的文章。

952

2023.10.23

php连接mssql数据库的方法
php连接mssql数据库的方法

php连接mssql数据库的方法有使用PHP的MSSQL扩展、使用PDO等。想了解更多php连接mssql数据库相关内容,可以阅读本专题下面的文章。

1418

2023.10.23

html怎么上传
html怎么上传

html通过使用HTML表单、JavaScript和PHP上传。更多关于html的问题详细请看本专题下面的文章。php中文网欢迎大家前来学习。

1234

2023.11.03

PHP出现乱码怎么解决
PHP出现乱码怎么解决

PHP出现乱码可以通过修改PHP文件头部的字符编码设置、检查PHP文件的编码格式、检查数据库连接设置和检查HTML页面的字符编码设置来解决。更多关于php乱码的问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1447

2023.11.09

php文件怎么在手机上打开
php文件怎么在手机上打开

php文件在手机上打开需要在手机上搭建一个能够运行php的服务器环境,并将php文件上传到服务器上。再在手机上的浏览器中输入服务器的IP地址或域名,加上php文件的路径,即可打开php文件并查看其内容。更多关于php相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1306

2023.11.13

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

43

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
进程与SOCKET
进程与SOCKET

共6课时 | 0.3万人学习

Redis+MySQL数据库面试教程
Redis+MySQL数据库面试教程

共72课时 | 6.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号