[GH-ISSUE #3279] [Feature Request] 支持把之前的连接踢掉 #2628

Closed
opened 2026-05-05 13:41:45 -06:00 by gitea-mirror · 9 comments
Owner

Originally created by @kingsimba on GitHub (Jan 31, 2023).
Original GitHub issue: https://github.com/fatedier/frp/issues/3279

Describe the feature request

问题描述

我们设备是移动使用的。当 WIFI 信号变差时,会修改路由表切换到 4G,这就导致了 client 经常意外掉线 (后附详细的复现方法)。

如果 client 意外掉线。重启时,会报 port already used。

d205c26480/server/ports/ports.go (L126)

必须等60-90秒,server 端才会自动把老的 client 端口释放掉。

d205c26480/server/control.go (L429)

然后 client 才能再次成功连接。

建议解决方法

有两个解决想法,仅供参考:

  1. 既然已经使用了 token 认证。可以认为是授信环境。在授信环境中,有新的连接一律不要拒绝,立刻把老的踢掉线。
  2. 第一次登录时,server 端返回一个随机的key。client 重连时,带上这个key来认证。如果 key 匹配,则立刻把老的踢掉线。

对于我们的使用场景,方案1已经足够。希望考虑支持。

详细复现步骤

  1. 机器同时安装 4G 网卡 和 WIFI。

ip ro 第一条 10.10.40.1 wlan0 是 WIFI 的路由。默认优先级最高。192.168.100.1 usb0 是 4G 网卡,优先级第二。

$ ip ro
default via 10.10.40.1 dev wlan0 metric 1
default via 192.168.100.1 dev usb0 proto dhcp metric 77
default via 10.10.40.1 dev wlan0 proto dhcp metric 88
10.10.40.0/24 dev wlan0 proto kernel scope link src 10.10.40.158 metric 88
169.254.0.0/16 dev usb0 scope link metric 1000
192.168.100.0/24 dev usb0 proto kernel scope link src 192.168.100.35 metric 77
  1. 启动 frpc。
  2. 删除第一条路由。删除后,4G 网卡生效。此时 frpc 无法和frps 通讯。
$ sudo ip route del default via 10.10.40.1 dev wlan0 metric 1
  1. 杀掉 frpc,重启它。
  2. 就会看到 Port Already Used 报错。

Describe alternatives you've considered

No response

Affected area

  • Docs
  • Installation
  • Performance and Scalability
  • Security
  • User Experience
  • Test and Release
  • Developer Infrastructure
  • Client Plugin
  • Server Plugin
  • Extensions
  • Others
Originally created by @kingsimba on GitHub (Jan 31, 2023). Original GitHub issue: https://github.com/fatedier/frp/issues/3279 ### Describe the feature request ### 问题描述 我们设备是移动使用的。当 WIFI 信号变差时,会修改路由表切换到 4G,这就导致了 client 经常意外掉线 (后附详细的复现方法)。 如果 client 意外掉线。重启时,会报 port already used。 https://github.com/fatedier/frp/blob/d205c264807b49f773f37a1efeeea86f39637e99/server/ports/ports.go#L126 必须等60-90秒,server 端才会自动把老的 client 端口释放掉。 https://github.com/fatedier/frp/blob/d205c264807b49f773f37a1efeeea86f39637e99/server/control.go#L429 然后 client 才能再次成功连接。 ### 建议解决方法 有两个解决想法,仅供参考: 1. 既然已经使用了 token 认证。可以认为是授信环境。在授信环境中,有新的连接一律不要拒绝,立刻把老的踢掉线。 2. 第一次登录时,server 端返回一个随机的key。client 重连时,带上这个key来认证。如果 key 匹配,则立刻把老的踢掉线。 对于我们的使用场景,方案1已经足够。希望考虑支持。 ### 详细复现步骤 1. 机器同时安装 4G 网卡 和 WIFI。 `ip ro` 第一条 10.10.40.1 wlan0 是 WIFI 的路由。默认优先级最高。192.168.100.1 usb0 是 4G 网卡,优先级第二。 ``` $ ip ro default via 10.10.40.1 dev wlan0 metric 1 default via 192.168.100.1 dev usb0 proto dhcp metric 77 default via 10.10.40.1 dev wlan0 proto dhcp metric 88 10.10.40.0/24 dev wlan0 proto kernel scope link src 10.10.40.158 metric 88 169.254.0.0/16 dev usb0 scope link metric 1000 192.168.100.0/24 dev usb0 proto kernel scope link src 192.168.100.35 metric 77 ``` 2. 启动 frpc。 3. 删除第一条路由。删除后,4G 网卡生效。此时 frpc 无法和frps 通讯。 ``` $ sudo ip route del default via 10.10.40.1 dev wlan0 metric 1 ``` 4. 杀掉 frpc,重启它。 5. 就会看到 Port Already Used 报错。 ### Describe alternatives you've considered _No response_ ### Affected area - [ ] Docs - [ ] Installation - [ ] Performance and Scalability - [X] Security - [X] User Experience - [ ] Test and Release - [ ] Developer Infrastructure - [ ] Client Plugin - [ ] Server Plugin - [ ] Extensions - [ ] Others
gitea-mirror 2026-05-05 13:41:45 -06:00
Author
Owner

@fatedier commented on GitHub (Jan 31, 2023):

不重启 frpc,无法恢复吗?不是很清楚上面修改路由表后的行为。

不采用新的客户端连接替换掉旧的,是为了避免某些场景下循环竞争,来回替换,更加不稳定。

你上面描述的第二点,当前已经有实现了,但是由于信息存放在内存中,所以重启后就不存在了。主要针对的场景是网络频繁中断和恢复的时候,frpc 在恢复后可以重新连接上 frps,这个时候能够明确知道旧的客户端的元数据是脏数据了,所以可以立即清理掉。

<!-- gh-comment-id:1409850040 --> @fatedier commented on GitHub (Jan 31, 2023): 不重启 frpc,无法恢复吗?不是很清楚上面修改路由表后的行为。 不采用新的客户端连接替换掉旧的,是为了避免某些场景下循环竞争,来回替换,更加不稳定。 你上面描述的第二点,当前已经有实现了,但是由于信息存放在内存中,所以重启后就不存在了。主要针对的场景是网络频繁中断和恢复的时候,frpc 在恢复后可以重新连接上 frps,这个时候能够明确知道旧的客户端的元数据是脏数据了,所以可以立即清理掉。
Author
Owner

@kingsimba commented on GitHub (Jan 31, 2023):

能指一下第二点对应的代码么?
我测试,如果不杀进程,只是把 frpc.ini 中的 heartbeat_timout 和 heartbeat_interval 改短,可以使得 frpc 更快的重连。(印证了你的说法)。

但是,这么做的话,高层代理的 HTTP 连接会断开。我们希望代理的 HTTP 最好不断,有可能实现么?

<!-- gh-comment-id:1409859708 --> @kingsimba commented on GitHub (Jan 31, 2023): 能指一下第二点对应的代码么? 我测试,如果不杀进程,只是把 frpc.ini 中的 heartbeat_timout 和 heartbeat_interval 改短,可以使得 frpc 更快的重连。(印证了你的说法)。 但是,这么做的话,高层代理的 HTTP 连接会断开。我们希望代理的 HTTP 最好不断,有可能实现么?
Author
Owner

@kingsimba commented on GitHub (Jan 31, 2023):

我们切换路由后,之所以重启 frpc,是为了尽快触发重连,不要等 client 端的 heartbeat_timeout。那是否可以把 key 保存到文件中,使得 client 重启后,能读取到这个 key 呢?

<!-- gh-comment-id:1409860943 --> @kingsimba commented on GitHub (Jan 31, 2023): 我们切换路由后,之所以重启 frpc,是为了尽快触发重连,不要等 client 端的 heartbeat_timeout。那是否可以把 key 保存到文件中,使得 client 重启后,能读取到这个 key 呢?
Author
Owner

@fatedier commented on GitHub (Jan 31, 2023):

正常网络短暂中断,之后恢复的场景,连接是不会断开的,恢复后可以正常通信。但是修改路由表的操作,可能确实只能依靠超时来中断之前的 TCP 连接。

不过你可以试试使用 quic 协议,因为基于 udp,理论上上面的场景下也是可以实现会话保持的。如果有测试结果,也可以同步一下。

那是否可以把 key 保存到文件中,使得 client 重启后,能读取到这个 key 呢?

当前的设计基本上除了写日志都不会在用户机器有额外的操作,会增加一定的复杂度,包括启动多个程序时的行为。如果不是非常必要,尽量不写用户磁盘。

<!-- gh-comment-id:1409871957 --> @fatedier commented on GitHub (Jan 31, 2023): 正常网络短暂中断,之后恢复的场景,连接是不会断开的,恢复后可以正常通信。但是修改路由表的操作,可能确实只能依靠超时来中断之前的 TCP 连接。 不过你可以试试使用 quic 协议,因为基于 udp,理论上上面的场景下也是可以实现会话保持的。如果有测试结果,也可以同步一下。 > 那是否可以把 key 保存到文件中,使得 client 重启后,能读取到这个 key 呢? 当前的设计基本上除了写日志都不会在用户机器有额外的操作,会增加一定的复杂度,包括启动多个程序时的行为。如果不是非常必要,尽量不写用户磁盘。
Author
Owner

@kingsimba commented on GitHub (Jan 31, 2023):

好,我试试 quic。

另外,能否给 frpc 增加外界通知立即重连的能力(比如使用 xmlrpc 调用啥的) ?就可以已知网络肯定断了的时候,主动发起一次重连,从而避免了等待超时。当然,引入 xmlrpc 等调用机制,又增加了复杂度。

<!-- gh-comment-id:1409981096 --> @kingsimba commented on GitHub (Jan 31, 2023): 好,我试试 quic。 另外,能否给 frpc 增加外界通知立即重连的能力(比如使用 xmlrpc 调用啥的) ?就可以已知网络肯定断了的时候,主动发起一次重连,从而避免了等待超时。当然,引入 xmlrpc 等调用机制,又增加了复杂度。
Author
Owner

@fatedier commented on GitHub (Jan 31, 2023):

另外,能否给 frpc 增加外界通知立即重连的能力

如果实现不复杂的话,可以考虑。

<!-- gh-comment-id:1409996928 --> @fatedier commented on GitHub (Jan 31, 2023): > 另外,能否给 frpc 增加外界通知立即重连的能力 如果实现不复杂的话,可以考虑。
Author
Owner

@wurong98 commented on GitHub (Jan 31, 2023):

frp_0.46.1_linux_amd64
错误日志

/frpc -c frpc.ini 
2023/01/31 19:10:01 failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/lucas-clemente/quic-go/wiki/UDP-Receive-Buffer-Size for details.
2023/01/31 19:10:06 [W] [service.go:133] login to server failed: timeout: no recent network activity
timeout: no recent network activity

配置信息

[common]
server_addr = 127.0.0.1
server_port = 7000
quic_bind_port = 7002
protocol = quic

[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 6000

请问一下quic是如何配置的呢?有什么需要注意的?

<!-- gh-comment-id:1410171095 --> @wurong98 commented on GitHub (Jan 31, 2023): frp_0.46.1_linux_amd64 错误日志 ``` /frpc -c frpc.ini 2023/01/31 19:10:01 failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/lucas-clemente/quic-go/wiki/UDP-Receive-Buffer-Size for details. 2023/01/31 19:10:06 [W] [service.go:133] login to server failed: timeout: no recent network activity timeout: no recent network activity ``` 配置信息 ``` [common] server_addr = 127.0.0.1 server_port = 7000 quic_bind_port = 7002 protocol = quic [ssh] type = tcp local_ip = 127.0.0.1 local_port = 22 remote_port = 6000 ``` 请问一下quic是如何配置的呢?有什么需要注意的?
Author
Owner

@wurong98 commented on GitHub (Jan 31, 2023):

frp_0.46.1_linux_amd64 错误日志

/frpc -c frpc.ini 
2023/01/31 19:10:01 failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/lucas-clemente/quic-go/wiki/UDP-Receive-Buffer-Size for details.
2023/01/31 19:10:06 [W] [service.go:133] login to server failed: timeout: no recent network activity
timeout: no recent network activity

配置信息

[common]
server_addr = 127.0.0.1
server_port = 7000
quic_bind_port = 7002
protocol = quic

[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 6000

请问一下quic是如何配置的呢?有什么需要注意的?

sudo sysctl -w net.core.rmem_max=2500000
之后存在
2023/01/31 20:00:11 [W] [service.go:133] login to server failed: timeout: no recent network activity
timeout: no recent network activity
请问下如何配置quic协议呢?

<!-- gh-comment-id:1410222771 --> @wurong98 commented on GitHub (Jan 31, 2023): > frp_0.46.1_linux_amd64 错误日志 > > ``` > /frpc -c frpc.ini > 2023/01/31 19:10:01 failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/lucas-clemente/quic-go/wiki/UDP-Receive-Buffer-Size for details. > 2023/01/31 19:10:06 [W] [service.go:133] login to server failed: timeout: no recent network activity > timeout: no recent network activity > ``` > > 配置信息 > > ``` > [common] > server_addr = 127.0.0.1 > server_port = 7000 > quic_bind_port = 7002 > protocol = quic > > [ssh] > type = tcp > local_ip = 127.0.0.1 > local_port = 22 > remote_port = 6000 > ``` > > 请问一下quic是如何配置的呢?有什么需要注意的? sudo sysctl -w net.core.rmem_max=2500000 之后存在 2023/01/31 20:00:11 [W] [service.go:133] login to server failed: timeout: no recent network activity timeout: no recent network activity 请问下如何配置quic协议呢?
Author
Owner

@github-actions[bot] commented on GitHub (Mar 3, 2023):

Issues go stale after 30d of inactivity. Stale issues rot after an additional 7d of inactivity and eventually close.

<!-- gh-comment-id:1452833684 --> @github-actions[bot] commented on GitHub (Mar 3, 2023): Issues go stale after 30d of inactivity. Stale issues rot after an additional 7d of inactivity and eventually close.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: github-starred/frp#2628
No description provided.