amoxic opened a new issue, #3530:
URL: https://github.com/apache/brpc/issues/3530

   **Describe the bug(问题描述)**
   
   配置了 `ChannelOptions::client_host` 和 `device_name` 的 TCP channel,在 socket 
失败并经过 health-check/revive 后,会丢失显式的源 IP 绑定。
   
   首次建连执行 `SO_BINDTODEVICE` 和 `bind(配置IP:0)`。但 `WaitAndReset()` 将 `_local_side` 
清为 `0.0.0.0:0`,仍保留 `_device_name`,导致后续 health-check 探测连接以及实际 RPC 
重建的连接只绑定设备,不再调用 `bind()`。
   
   根据源码分析,这应是 #3179 引入客户端绑定功能时遗漏的连接恢复路径:配置的绑定地址与运行中的实际本地端点共用了 `_local_side`。
   
   1. `OnCreated()` 保存 `options.local_side` 和 `options.device_name`。
   2. 首次连接建立后,`ResetFileDescriptor()` 通过 `getsockname()` 将 `_local_side` 覆盖为实际 
IP:临时端口。
   3. socket 失败后,`WaitAndReset()` 关闭旧 fd、清空 `_local_side`,但保留 `_device_name`。
   4. `CheckHealth()` 调用 `Connect()`:继续设置 `SO_BINDTODEVICE`,但因本地 IP 为 ANY 而跳过 
`bind()`。成功的探测 fd 被直接关闭,没有经过 `ResetFileDescriptor()` 安装,因此也不会回填 `_local_side`。
   5. `Revive()` 恢复 socket 的可用状态。下一次业务写入经 `ConnectIfNot()` 重建连接,仍然跳过 IP bind。
   
   以下源码链接固定到本次检查的上游 master commit `ffaa33e7395af6d58b8ac0d07b518ecd6023a08d`:
   
   - [Socket 
初始化](https://github.com/apache/brpc/blob/ffaa33e7395af6d58b8ac0d07b518ecd6023a08d/src/brpc/socket.cpp#L744)
   - [WaitAndReset 
清空本地端点](https://github.com/apache/brpc/blob/ffaa33e7395af6d58b8ac0d07b518ecd6023a08d/src/brpc/socket.cpp#L1017)
   - [Connect 独立判断设备绑定和 IP 
bind](https://github.com/apache/brpc/blob/ffaa33e7395af6d58b8ac0d07b518ecd6023a08d/src/brpc/socket.cpp#L1282)
   - [health-check 的 reset/check/revive 
顺序](https://github.com/apache/brpc/blob/ffaa33e7395af6d58b8ac0d07b518ecd6023a08d/src/brpc/details/health_check.cpp#L184)
   
   **To Reproduce(复现方法及已有验证)**
   
   下面是根据源码路径整理的 brpc 复现步骤,尚未完成独立的 brpc 回归程序及其系统调用抓取:
   
   1. 使用非本机 TCP 服务端,创建持久的 `connection_type = "single"` channel,配置有效的本地 
`client_host` 及对应 `device_name`。
   2. 成功发送一次 RPC,保留该 channel。
   3. 让测试服务端关闭或 reset 已接受的连接,使客户端 socket 被 brpc 标记为 failed;保持或恢复服务端监听,使 
health-check 可以成功。
   4. 等待该 socket revive,再经同一 channel 发送 RPC。
   5. 跟踪 `socket`、`setsockopt`、`bind`、`connect`,同时检查临时 health-check fd 和后续业务 
fd。根据上述源码路径,只有初次连接执行 `bind(配置IP:0)`。
   
   已有现场日志确认:后续发生 TCP 故障的同一 SocketId、同一 socket 对象,在故障之前已经历过 
revive。这支持生命周期前置条件,但日志本身不能证明当时具体执行了哪些 bind 系统调用。
   
   另外,已用独立的 Linux TCP socket 测试验证“丢失 bind”可能带来的四元组冲突影响。测试程序逻辑如下:
   
   - 建立一条设置了 `SO_BINDTODEVICE` 的客户端长连接 A,仅切换它是否额外调用 `bind(本地IP:0)`。
   - 创建不设置设备绑定、也不执行 bind 的 socket B,连接同一服务端。
   - 在隔离 network namespace 中使用小范围临时端口池;A 获得端口 P 后,预留其余端口,使 B 只能选择 P 
或连接失败。两个客户端均关闭 `SO_REUSEADDR`。
   - A 只绑定设备时:B 第一次尝试即复用相同线上四元组并连接成功,服务端观察到原 A 连接被 reset。
   - A 同时执行 `bind(本地IP:0)` 时:B 的 4 次尝试均返回 `EADDRNOTAVAIL`,服务端旧连接未被 reset。
   
   这组实验直接使用 Linux socket,不调用 brpc;它验证的是退化后连接配置在所测内核上的影响,不等同于完整的 brpc revive 
复现,也不代表所有 Linux 版本都存在同样的碰撞行为。
   
   **Expected behavior(预期行为)**
   
   显式配置的客户端源 IP 应在 channel 生命周期内始终生效,包括 health-check 探测连接以及 revive 
后重建的业务连接。配置的设备绑定也应保留。
   
   一次可恢复的连接失败不应静默改变客户端绑定策略。
   
   **Versions(版本信息)**
   
   - OS:Linux x86_64。独立 TCP 对照实验内核为 `5.14.0-162.6.1.el9_1.x86_64`;原故障节点内核为 
`5.14.0-570.17.1.el9_6.x86_64`。
   - Compiler:尚未采集原故障二进制的精确编译器版本。
   - brpc:下游使用的包版本为 `1.18.0-rc1`,源码 commit 为 
`3fe5abfcdc3285422045b98742c998413f980e00`。2026-09-07 检查的上游 master 
`ffaa33e7395af6d58b8ac0d07b518ecd6023a08d` 仍包含相同的相关逻辑;本次对上游 master 
做了源码核对,未重新构建运行。
   - protobuf:独立 TCP 对照实验不依赖 protobuf;原故障二进制实际链接的版本尚未独立核实。
   
   **Additional context/screenshots(补充说明)**
   
   建议将“配置的本地绑定端点”与“实际连接端点”分开保存,所有 `Connect()` 均使用持久配置决定是否执行 bind;`_local_side` 
继续表达运行态,在 reset 时可以清空。
   
   不宜直接删除 `_local_side` 的清零逻辑:已建立连接后,它包含实际临时端口,直接保留可能让重连尝试绑定旧端口,而非原配置的端口 0。
   
   四元组冲突属于额外的影响证据。本 issue 的核心是:即使某个内核或拓扑不会产生碰撞,brpc 在恢复过程中丢失用户配置的源 IP 
bind,仍然是需要修复的行为。
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to