学习在Swoole源码中查询 Websocket 的连接问题

.markdown-body{word-break:break-word;line-height:1.75;font-weight:400;font-size:15px;overflow-x:hidden;color:#333}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{line-height:1.5;margin-top:35px;margin-bottom:10px;padding-bottom:5px}.markdown-body h1{font-size:30px;margin-bottom:5px}.markdown-body h2{padding-bottom:12px;font-size:24px;border-bottom:1px solid #ececec}.markdown-body h3{font-size:18px;padding-bottom:0}.markdown-body h4{font-size:16px}.markdown-body h5{font-size:15px}.markdown-body h6{margin-top:5px}.markdown-body p{line-height:inherit;margin-top:22px;margin-bottom:22px}.markdown-body img{max-width:100%}.markdown-body hr{border:none;border-top:1px solid #ddd;margin-top:32px;margin-bottom:32px}.markdown-body code{word-break:break-word;border-radius:2px;overflow-x:auto;background-color:#fff5f5;color:#ff502c;font-size:.87em;padding:.065em .4em}.markdown-body code,.markdown-body pre{font-family:Menlo,Monaco,Consolas,Courier New,monospace}.markdown-body pre{overflow:auto;position:relative;line-height:1.75}.markdown-body pre>code{font-size:12px;padding:15px 12px;margin:0;word-break:normal;display:block;overflow-x:auto;color:#333;background:#f8f8f8}.markdown-body a{text-decoration:none;color:#0269c8;border-bottom:1px solid #d1e9ff}.markdown-body a:active,.markdown-body a:hover{color:#275b8c}.markdown-body table{display:inline-block!important;font-size:12px;width:auto;max-width:100%;overflow:auto;border:1px solid #f6f6f6}.markdown-body thead{background:#f6f6f6;color:#000;text-align:left}.markdown-body tr:nth-child(2n){background-color:#fcfcfc}.markdown-body td,.markdown-body th{padding:12px 7px;line-height:24px}.markdown-body td{min-width:120px}.markdown-body blockquote{color:#666;padding:1px 23px;margin:22px 0;border-left:4px solid #cbcbcb;background-color:#f8f8f8}.markdown-body blockquote:after{display:block;content:””}.markdown-body blockquote>p{margin:10px 0}.markdown-body ol,.markdown-body ul{padding-left:28px}.markdown-body ol li,.markdown-body ul li{margin-bottom:0;list-style:inherit}.markdown-body ol li .task-list-item,.markdown-body ul li .task-list-item{list-style:none}.markdown-body ol li .task-list-item ol,.markdown-body ol li .task-list-item ul,.markdown-body ul li .task-list-item ol,.markdown-body ul li .task-list-item ul{margin-top:0}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-top:3px}.markdown-body ol li{padding-left:6px}@media (max-width:720px){.markdown-body h1{font-size:24px}.markdown-body h2{font-size:20px}.markdown-body h3{font-size:18px}}

Swoole教程栏目介绍如何查询Websocket的连接问题。

学习在Swoole源码中查询 Websocket 的连接问题

推荐:swoole教程

问题

我们项目的 Websocket Server 使用的 Swoole,最近在搭建 beta 环境的时候发现 Websocket 协议虽然升级成功了,但是会出现定时重连,心跳、数据也一直没有发送。项目的生产环境和 beta 一致,但是生产环境确没有这个问题。
学习在Swoole源码中查询 Websocket 的连接问题

定位问题

为了方便调试 Swoole,以下测试是在本地环境下进行。

查看 PHP 日志

在 PHP 日志里,发现一条错误日志: ErrorException: SwooleWebSocketServer::push(): the connected client of connection[47] is not a websocket client or closed,说明 Websocket 连接已经 close 了。

抓包

既然连接被 close 掉了,那我们来看看是谁主动关闭的连接。Swoole 监听的端口是 1215,通过 tcpdump -nni lo0 -X port 1215 可以看到,Swoole 在发出协议升级的响应报文后,又发出了 Fin 报文段,即 Swoole 主动断开了连接,所以才会出现浏览器显示 WebSocket 连接建立成功,但是又定时重连的问题。

10:22:58.060810 IP 127.0.0.1.1215 > 127.0.0.1.53823: Flags [P.], seq 1:185, ack 1372, win 6358, options [nop,nop,TS val 1981911666 ecr 1981911665], length 184    0x0000:  4500 00ec 0000 4000 4006 0000 7f00 0001  E.....@.@.......    0x0010:  7f00 0001 04bf d23f 9377 304a 6d2f 9604  .......?.w0Jm/..    0x0020:  8018 18d6 fee0 0000 0101 080a 7621 9272  ............v!.r    0x0030:  7621 9271 4854 5450 2f31 2e31 2031 3031  v!.qHTTP/1.1.101    0x0040:  2053 7769 7463 6869 6e67 2050 726f 746f  .Switching.Proto    0x0050:  636f 6c73 0d0a 5570 6772 6164 653a 2077  cols..Upgrade:.w    0x0060:  6562 736f 636b 6574 0d0a 436f 6e6e 6563  ebsocket..Connec    0x0070:  7469 6f6e 3a20 5570 6772 6164 650d 0a53  tion:.Upgrade..S    0x0080:  6563 2d57 6562 536f 636b 6574 2d41 6363  ec-WebSocket-Acc    0x0090:  6570 743a 2052 6370 3851 6663 446c 3146  ept:.Rcp8QfcDl1F    0x00a0:  776e 666a 6377 3862 4933 6971 7176 4551  wnfjcw8bI3iqqvEQ    0x00b0:  3d0d 0a53 6563 2d57 6562 536f 636b 6574  =..Sec-WebSocket    0x00c0:  2d56 6572 7369 6f6e 3a20 3133 0d0a 5365  -Version:.13..Se    0x00d0:  7276 6572 3a20 7377 6f6f 6c65 2d68 7474  rver:.swoole-htt    0x00e0:  702d 7365 7276 6572 0d0a 0d0a            p-server....10:22:58.060906 IP 127.0.0.1.53823 > 127.0.0.1.1215: Flags [.], ack 185, win 6376, options [nop,nop,TS val 1981911666 ecr 1981911666], length 0    0x0000:  4500 0034 0000 4000 4006 0000 7f00 0001  E..4..@.@.......    0x0010:  7f00 0001 d23f 04bf 6d2f 9604 9377 3102  .....?..m/...w1.    0x0020:  8010 18e8 fe28 0000 0101 080a 7621 9272  .....(......v!.r    0x0030:  7621 9272                                v!.r10:22:58.061467 IP 127.0.0.1.1215 > 127.0.0.1.53823: Flags [F.], seq 185, ack 1372, win 6358, options [nop,nop,TS val 1981911667 ecr 1981911666], length 0    0x0000:  4500 0034 0000 4000 4006 0000 7f00 0001  E..4..@.@.......    0x0010:  7f00 0001 04bf d23f 9377 3102 6d2f 9604  .......?.w1.m/..    0x0020:  8011 18d6 fe28 0000 0101 080a 7621 9273  .....(......v!.s    0x0030:  7621 9272                                v!.r复制代码

追踪 Swoole 源码

我们现在知道了是 Swoole 主动断开了连接,但它是在什么时候断开的,又为什么要断开呢?就让我们从源码一探究竟。

从抓包结果看,发出响应报文到 close 连接的时间很短,所以猜测是握手阶段出了问题。从响应报文可以看出,Websocket 连接是建立成功的,推测 swoole_websocket_handshake() 的结果应该是 true,那么连接应该是在 swoole_websocket_handshake() 里 close 的。

// // swoole_websocket_server.ccint swoole_websocket_onHandshake(swServer *serv, swListenPort *port, http_context *ctx){    int fd = ctx->fd;    bool success = swoole_websocket_handshake(ctx);    if (success)    {        swoole_websocket_onOpen(serv, ctx);    }    else    {        serv->close(serv, fd, 1);    }    if (!ctx->end)    {        swoole_http_context_free(ctx);    }    return SW_OK;}复制代码

追踪进 swoole_websocket_handshake() 里,前面部分都是设置响应的 header,响应报文则是在 swoole_http_response_end() 里发出的,它的结果也就是 swoole_websocket_handshake 的结果。

// swoole_websocket_server.ccbool swoole_websocket_handshake(http_context *ctx){    ...    swoole_http_response_set_header(ctx, ZEND_STRL("Upgrade"), ZEND_STRL("websocket"), false);    swoole_http_response_set_header(ctx, ZEND_STRL("Connection"), ZEND_STRL("Upgrade"), false);    swoole_http_response_set_header(ctx, ZEND_STRL("Sec-WebSocket-Accept"), sec_buf, sec_len, false);    swoole_http_response_set_header(ctx, ZEND_STRL("Sec-WebSocket-Version"), ZEND_STRL(SW_WEBSOCKET_VERSION), false);        ...    ctx->response.status = 101;    ctx->upgrade = 1;    zval retval;    swoole_http_response_end(ctx, nullptr, &retval);    return Z_TYPE(retval) == IS_TRUE;}复制代码

swoole_http_response_end() 代码中我们发现,如果 ctx->keepalive 为 0 的话则关闭连接,断点调试下发现还真就是 0。至此,连接断开的地方我们就找到了,下面我们就看下什么情况下 ctx->keepalive 设置为 1。

// swoole_http_response.ccvoid swoole_http_response_end(http_context *ctx, zval *zdata, zval *return_value){    if (ctx->chunk) {       ...    } else {        ...            if (!ctx->send(ctx, swoole_http_buffer->str, swoole_http_buffer->length))        {            ctx->send_header = 0;            RETURN_FALSE;        }     }    if (ctx->upgrade && !ctx->co_socket) {        swServer *serv = (swServer*) ctx->private_data;        swConnection *conn = swWorker_get_connection(serv, ctx->fd);        // 此时websocket_statue 已经是WEBSOCKET_STATUS_ACTIVE,不会走进这步逻辑        if (conn && conn->websocket_status == WEBSOCKET_STATUS_HANDSHAKE) {            if (ctx->response.status == 101) {                conn->websocket_status = WEBSOCKET_STATUS_ACTIVE;            } else {                /* connection should be closed when handshake failed */                conn->websocket_status = WEBSOCKET_STATUS_NONE;                ctx->keepalive = 0;            }        }    }    if (!ctx->keepalive) {        ctx->close(ctx);    }    ctx->end = 1;    RETURN_TRUE;}复制代码

最终我们找到 ctx->keepalive 是在 swoole_http_should_keep_alive() 里设置的。从代码我们知道,当 HTTP 协议是 1.1 版本时,keepalive 取决于 header 没有设置 Connection: close;当为 1.0 版本时,header 需设置 Connection: keep-alive

Websocket 协议规定,请求 header 里的 Connection 需设置为 Upgrade,所以我们需要改用 HTTP/1.1 协议。

int swoole_http_should_keep_alive (swoole_http_parser *parser){  if (parser->http_major > 0 && parser->http_minor > 0) {    /* HTTP/1.1 */    if (parser->flags & F_CONNECTION_CLOSE) {      return 0;    } else {      return 1;    }  } else {    /* HTTP/1.0 or earlier */    if (parser->flags & F_CONNECTION_KEEP_ALIVE) {      return 1;    } else {      return 0;    }  }}复制代码

解决问题

从上面的结论我们可以知道,问题的关键点在于请求头的 Connection 和 HTTP 协议版本。

后来问了下运维,生产环境的 LB 会在转发请求时,会将 HTTP 协议版本修改为 1.1,这也是为什么只有 beta 环境存在这个问题,nginx 的 access_log 也印证了这一点。

那么解决这个问题就很简单了,就是手动升级下 HTTP 协议的版本,完整的 nginx 配置如下。

upstream service {    server 127.0.0.1:1215;}server {    listen 80;    server_name dev-service.ts.com;    location / {        proxy_set_header Host $http_host;        proxy_set_header Scheme $scheme;        proxy_set_header SERVER_PORT $server_port;        proxy_set_header REMOTE_ADDR $remote_addr;        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;        proxy_set_header Upgrade $http_upgrade;        proxy_set_header Connection $connection_upgrade;        proxy_http_version 1.1;        proxy_pass http://service;    }}复制代码

重启 Nginx 后,Websocket 终于正常了~

以上就是学习在Swoole源码中查询 Websocket 的连接问题的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/81890.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月16日 00:00:43
下一篇 2025年11月16日 00:39:23

相关推荐

  • Livepeer(LPT)价格飙升150%,与口袋网络,白色岩石和Numeraire一起排名为高级表演者

    livepeer成为本周少数几个逆势上涨的山寨币之一,因市场再次见证了大量抛售交易,推动比特币逼近105,000美元。 Livepeer(LPT)今日价格暴涨150%,位列涨幅榜前列,因市场经历了一轮抛售狂潮,促使比特币冲向105,000美元。 作为去中心化AI协议Livepeer的原生代币,LPT…

    2025年12月8日
    000
  • Ruvi AI(Ruvi)代币卖出了其创纪录的预售,筹集了140万美元

    在加密货币的竞争性世界中,新玩家不断出现,但是很少有人能吸引ruvi ai等聪明的投资者的注意。 在加密货币的动态范围内,新的竞争者不断出现,但很少有人能吸引像Ruvi AI这样的智能投资者的注意力。该项目以预售的价格仅为0.015美元的低入口价格开始旅程,并以其预售量粉碎了记录,售出了1.3亿个代…

    2025年12月8日
    000
  • 比特币最近的新历史高度高于100,000美元的新兴速度受到了大量机构投资的推动

    这种进展不仅体现在价格方面,还伴随着强大的机构推动力和有利的宏观经济环境。 比特币的价格似乎并未显现出减速的迹象,继续在历史高位不断攀升,业内专家预计到2025年第四季度,潜在的上涨目标或将达到16万美元。 比特币突破了11万美元关口,为刷新历史高点创造了条件。 比特币目前的交易价格约为109,45…

    2025年12月8日
    000
  • Ruvi AI是新的Shiba INU:到2025年的100倍增长潜力

    加密货币市场正处于快速扩张阶段,并非所有项目都能跟上步伐。曾被视为模因币领军者的柴犬币(shiba inu)似乎正逐渐褪去昔日光环。 加密货币市场发展迅猛,众多项目难以同步跟进。柴犬币(Shiba Inu),作为模因币中的明星,因投资者转而青睐具备实际应用场景及长远发展潜力的项目,目前似乎正逐步失去…

    2025年12月8日
    000
  • AIOZ网络宣布与NEO区块链进行战略合作

    通过此次合作,aioz成为depin解决方案供应商。 AIOZ网络已宣布与NEO区块链建立战略合作伙伴关系,将去中心化基础设施与NEO的EVM兼容Sidechain(Chain X)整合在一起。通过这一联盟,Aioz担当Depin解决方案供应商的角色。 这种结合让Aioz的去中心化服务(分割视频流、…

    2025年12月8日
    000
  • 比特币鲸在不到一周的时间内积累了20,000 BTC,增加了对BTC的赌注

    根据加密货币分析师及交易员阿里·马丁内斯(ali martinez)撰写的文章,比特币巨鲸在短短几天内购入超过20,000枚btc。 加密货币分析师兼商人阿里·马丁内斯指出,比特币巨鲸正在积极增持更多BTC,进一步增加其对全球顶级加密货币的投资。 依据分析师发布的内容,Santiment提供的数据显…

    2025年12月8日
    000
  • 哪些加密货币在2025年可以看到重大收益?

    随着加密货币市场的再度崛起,人们正积极寻找2025年最具潜力的加密货币,尤其是那些具备实用场景并拥有强劲增长前景的项目。 加密货币市场的热度持续上升,众多投资者开始关注2025年最具潜力的加密货币。这些项目通常能提供实际的应用价值,并展现出在牛市后期的强大增长潜力。 比特币突破111,000美元大关…

    2025年12月8日
    000
  • 在Ozak AI翻转剧本之前,Doge可以打1美元吗?

    长期以来,dogecoin(狗狗币)一直是加密货币领域备受欢迎的模因币之一,凭借其可爱的柴犬形象以及埃隆·马斯克等知名人士的支持而广受关注。 埃隆·马斯克偏爱的这种加密货币再次成为焦点,因为一些投机者预计其价格可能升至1美元。与此同时,一个相对低调的项目——Ozak AI——在预售阶段以0.003美…

    2025年12月8日
    000
  • Web3 AI的10,000x预测使其成为加密市场中的下一个大事!蒙罗(Monero

    $777,000的奖励能否与10,000倍的回报机会抗衡?4月份,shiba inu(shib)创造了超过100位新百万富翁! Shiba Inu(Shib)迅速成为加密货币爱好者热议的话题,特别是由于其创造百万富翁的巨大潜力。近期的报道指出,Shib在4月份的价格上涨帮助产生了109位新的百万富翁…

    2025年12月8日
    000
  • 惩罚者硬币可能很快竞争雪崩(Avax)和Chainlink(链接)

    随着加密货币市场的继续成熟,敏锐的投资者总是在寻找最有前途的加密货币,不仅提供短期的资产 随着加密货币市场的继续成熟,敏锐的投资者总是在寻找最有前途的加密货币,不仅可以提供短期增长的资产,而且还提供长期可持续性,强大的社区支持和现实世界中的实用性。 尽管诸如Avalanche(Avax)和Chain…

    2025年12月8日
    000
  • Unilabs(Unil)在初始硬币产品中粉碎了100万美元的里程碑

    在过去的几周里,以太坊(eth)和solana的价格都出现了显著的上涨。这两种加密货币的涨幅均达到了两位数。 受比特币价格激增11万美元的影响,这些加密货币的价格均有显著提升。市场专家卡莱奥和亨利等人也纷纷看好以太坊和Solana的未来走势,激励了许多交易者。 与此同时,一种新型加密货币——Unil…

    2025年12月8日
    000
  • 灰度推出全新人工智能加密货币板块,涵盖20种山寨币

    知名资产管理公司灰度投资(grayscale investments)近日宣布推出一个全新的人工智能加密货币板块,专注于与ai相关的加密项目。该板块包括20种精选的山寨币,这些项目被认为在人工智能与区块链融合领域具有重要潜力。灰度此举旨在为投资者提供一个结构化的方式,以参与这一快速发展的技术交汇点。…

    2025年12月8日 好文分享
    000
  • 据Coingecko称

    加密货币市场持续迅猛发展,新项目与老牌巨头共同吸引了市场的目光。 加密货币市场热度持续攀升,伴随新项目的转型以及投资者的关注点转移。Coingecko在其最新发布的涵盖5月24日至30日当周的报告中,列出了前20个趋势硬币,展现了新兴生态系统与主流区块链平台之间引人注目的结合。 超级流动性(HYPE…

    2025年12月8日
    000
  • Puffverse(PFVS)价格预测2025年-2030:未来能达到 1 美元吗?

    随着元宇宙和游戏市场吸引越来越多的投资者关注,puffverse (pfvs) 有望成为 gamefi 和娱乐平台的参与者。2025 年,pfvs 价格有望维持在 0.07 美元左右,潜在的上涨动力取决于接受度、游戏内经济状况以及整体市场情绪。随着平台参与度和 nft 集成度的提升,价格支撑位有望在…

    2025年12月8日
    000
  • 什么是Sentient AI ?SETAI 代币及空投参与方式介绍(新手指南)

    什么是Sentient AI ?SETAI 代币及空投参与方式介绍(新手指南) Sentient AI是一个专注于打造去中心化通用人工智慧(AGI)的创新项目,穿透结合区块链与人工智慧技术,实现由社群建立、拥有并控制的AI模型。该专案获得大量风险资本支持,旨在打造一个开放、透明且可参与的AI生态系统…

    2025年12月8日
    000
  • Alaya(AGT)是什么?AGT价格预测 2025年 – 2030年

    alaya 治理代币 (agt)凭借其与去中心化平台的整合以及社区驱动决策的新模式,在 web3 和治理代币领域蓬勃发展。随着整体市场再次对治理代币和 web3 基础设施表现出兴趣,投资者希望了解 agt 的短期和长期价格前景。预计 2025 年 agt 的平均交易价格约为 0.03155 美元,价…

    2025年12月8日
    000
  • RWA,AI和IP逐渐成为Web3世界中三个最具想象力的主要线条。

    rwa在2023年引发了热情,现在进入了更精致的资产分类阶段。 ai在2024年爆发,为nvidia带来了历史性的市场价值飞跃。 ip曾经被视为“冷轨道”,由于ai的快速开发而被重新定义为web3的“能量引擎”,这既是数据资产的内容的来源,也是数据资产的核心结构。 现实世界资产(RWA),人工智能(…

    2025年12月8日
    000
  • Upbit列表羊群,堡垒,Pokt和LPT

    韩国最大的虚拟货币交易平台upbit宣布,将在其现货交易市场上新增四个替代币(altcoins)。 韩国最大的虚拟货币交易平台UPBIT计划在现货市场上新增四个替代币(Altcoins)。这些代币预计将在周二上市,分别是Flock.io(Flock)、Forta(Fort)、Pocket Netwo…

    2025年12月8日
    000
  • 惩罚者硬币:下一个uniswap或链链接?

    在加密货币领域里,找到同时具备娱乐性、实用性以及长期增值潜力的项目并不常见。不过,punisher coin(简称$pun)正逐渐崭露头角,成为一个与众不同的竞争者,它巧妙地融合了模因币的传播力与严肃区块链项目的精心设计。 在飞速发展的加密市场中,要找到能够完美结合娱乐、实用性和长期成长潜力的项目并…

    2025年12月8日
    000
  • 区块链项目的三大分类介绍:公链、私链与联盟链的优点分析!

    区块链本质上是一个去中心化的数据库,它不依赖于第三方,而是通过自身的节点进行网络数据的存储、验证、传递和交流。经过多年的运作,区块链技术已经出现了日新月异的发展,其应用范围已经涵盖了金融、游戏、产权、等多个领域。今天这篇医疗文章我们将盘点区块链的类型和特征。 区块链项目的三大分类介绍:公链、私链与联…

    2025年12月8日
    000

发表回复

登录后才能评论
关注微信