cnbatch/udphop

网络不好/断线会自动退出

bhzhu203 opened this issue · 31 comments

网络不好/断线会自动退出,有没有参数可以让它无限断线重连而程序不退出?谢谢

应该是有bug,我需要在Linux环境专门测试下才行。

由于我个人主要用Windows和FreeBSD,所以没怎么在Linux长时间测试过,有些隐藏Bug应该就没排查出来

发布了新的版本,希望有用

发布了新的版本,希望有用

好的 我试一下

发布了新的版本,希望有用

我觉得正确的做法应该倾向于以下2点:

①心跳保活,确保端口hop之前,连接一直有效,虽然设计上“单个 Session 超过 3 分钟”,但实际网络环境中,udp连接极大概率存活不了那么久,我这里实测在60-90秒的样子;

②端口hop成功之前,保持之前的连接,随后平移过去,一个很好的思路可能是将quic作为服务端<—>客户端的通信通道,因为quic可以链接平移,修改底层udp端口,不会影响quic连接;

仅代表个人拙见,抛砖引玉,如有不妥之处,还望不吝斧正

cat /tmp/udphp.log
error_found: No
Servers: 0
Clients: 1
start_up() running in client mode (UDP)
Host not found (authoritative)
Host not found (authoritative)
Host not found (authoritative)
Host not found (authoritative)
terminate called after throwing an instance of 'std::system_error'
what(): open: Too many open files

又自动退出了

感谢两位的反馈!果然各地的运营商设置都各不相同,我也应该设置得灵活一点才行

Host not found (authoritative)

看起来是重播的间隙比较大,原先的4次重试、共12秒不够用。现在改成了优先使用缓存着的地址,如果没有缓存再重新解析地址,并且重试时间延长到了30次、每次间隔3秒(共90秒),这样应该就够用

心跳保活

保持之前的连接,随后平移过去

其实现有的设计是有自动平移的,但就没心跳保活。

如果运营商清理掉了原有UDP连接,那么后续的自动平移就无法生效,毕竟原有连接都不存在了,自然无从平移。

这么看来“心跳保活”是关键,所以现在加上了“心跳保活”,1秒1个包,对于两侧设备而言应该没什么压力。

还有个好处,顺便解决掉前面“Host not found”的错误了,心跳包就可以确保缓存一定会刷新,就算DNS短时间不可用都没问题。

cat /tmp/udphp.log error_found: No Servers: 0 Clients: 1 start_up() running in client mode (UDP) Host not found (authoritative) Host not found (authoritative) Host not found (authoritative) Host not found (authoritative) terminate called after throwing an instance of 'std::system_error' what(): open: Too many open files

又自动退出了

退出 不是无法处理描述符太多的问题吗

花了一晚上时间,发现问题是打开Log文件后忘了关闭以至于后续的打开操作死等到崩溃

于是顺带在新版本中fix好了

现在新版本(v0.7)的Keep Alive需要手动打开,在config文件中加入keep_alive=x(单位是秒),设为0表示关闭keep alive(默认值)

keep_alive 需要服务端和客户端同时配置吗

terminate called after throwing an instance of 'std::system_error'
what(): open: Too many open files

是要加大 ulimit -n的值吗

程序运行了一会就有几千个UDP连接 这些连接不会自动回收的吗

lsof -p 1342265 | wc
4842 43591 363596

图片

这些连接是不是大部分连接超时的

Keep Alive可以两边单独设置,根据需要可以两边都设。


有时部分UDP端口会无法及时回收,这种情况我在FreeBSD运行udphop的Server模式时遇到过,但仅限于强制退出才会出现(Debian 11和Fedora 37强制退出udphop都能立即回收端口),等待几十秒至一分钟才会被系统回收,正常连接不会这样。

没想到client模式在Linux的情况会如此不一样,我在Windows和FreeBSD没遇到过这样的怪事,UDP回收都很及时,一直都不知道会这样。

现在看来只好在UDP回收前主动调用一次disconnect。

超时可能也有关系,因为上一个error我误会是连接时间太短(与目标应用交互的UDP连接在180秒内完全无数据就主动释放,),于是增加到1小时。现在减少到20分钟,双管齐下。

有时候会出现 这样的报错,是不是端口被运营商屏蔽了 (多端口连接)我把进程结束掉重连就好了

❰bhzhu❙~❱✔≻ [2023-02-23 11:20:48 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:48 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:48 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:49 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:49 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:49 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:49 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:51 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:51 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:53 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:53 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:53 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:54 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:54 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:54 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:54 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:56 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:56 +0800] Cannot Send Data:
Invalid argument
❰bhzhu❙~❱✔≻ [2023-02-23 11:20:58 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:58 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:58 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:59 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:59 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:59 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:20:59 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:21:01 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:21:01 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:21:03 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:21:03 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:21:03 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:21:04 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:21:04 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:21:04 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:21:04 +0800] Cannot Send Data:
Invalid argument
❰bhzhu❙~❱✔≻ [2023-02-23 11:21:06 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:21:06 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:21:08 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:21:08 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:21:08 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:21:09 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:21:09 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:21:09 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:21:09 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:21:11 +0800] Cannot Send Data:
Invalid argument
[2023-02-23 11:21:11 +0800] Cannot Send Data:
Invalid argument

已经把 src/networks/connections.hpp 里的 “constexpr size_t TIMEOUT = 1; // second” 设置为1了

UDP链接还是会每秒新增一个,而且不会关闭 直至文件描述符用完到1024 退出

❰bhzhu❙~❱✔≻ lsof -p 1414336 |wc
   1003    9027   74252
❰bhzhu❙~❱✔≻ lsof -p 1414336 |wc
   1004    9036   74326
❰bhzhu❙~❱✔≻ lsof -p 1414336 |wc
   1005    9045   74400

constexpr size_t TIMEOUT

这个Timeout不能改太小,它指的是“本机应用↔udphop”这部分的连接超时,小到只有1秒就会导致几乎每时每刻都在自动断连,然后又自动建立新的session,这样会导致UDP连接数短时间内“爆炸”。


描述符只有1024个这么少,难怪会短时间内耗尽。

我看了下自己用的FreeBSD及其衍生版当中 ulimit -a 的open files数值,FreeBSD、opnsense都超过11万,GhostBSD甚至多达46万。没错,都是6位数。
云厂商提供的FreeBSD虚拟机中open files数值没那么大,但都有5位数。

怪不得我一直都碰不到这种文件描述符用尽的情况,在FreeBSD平台有足够的描述符,这样就有足够的时间给系统回收端口。

Linux平台确实应该用 ulimit -n 把 limit 数值改大一点。

另外我又看了下kcptun的readme,发现他们也建议调高 ulimit -n 的数值。

我是一直都不知道Linux的ulimit -n默认值会这么低,从来没想过需要手动调整。

关键也不是ulimit -n值低的问题 ,是连接不会回收,每秒增加一个连接,直至用完。调到10240也会用完

连接什么时候回收并不是我能干预的,这是内核(或者说,是网络栈)的事情,回收前的等待时间并不会短

https://stackoverflow.com/questions/22549044/why-is-port-not-immediately-released-after-the-socket-closes

唯一能做的就是ulimit -n设置非常高的数值

https://github.com/apernet/hysteria 用的也是多端口UDP传输,并没有出现那么多的连接数

❰bhzhu❙~❱✔≻ ps aux | grep hy
bhzhu 870893 0.0 0.0 47452 1808 ? S 2月14 0:00 /bin/bash /home/bhzhu/Desktop/scripts/startup/hysteria-jp.sh
bhzhu 870904 0.0 0.0 728688 16212 ? Sl 2月14 6:29 /home/bhzhu/hysteria-static -c /home/bhzhu/Desktop/scripts/startup/config-jp1 client
bhzhu 1511962 0.0 0.0 39936 4548 pts/6 S+ 17:28 0:00 grep --color=auto hy
❰bhzhu❙~❱✔≻ lsof -p 870904 | wc -l
52
❰bhzhu❙~❱✔≻ ps aux | grep udp
bhzhu 1507979 0.0 0.1 24196 19540 pts/11 Sl 16:32 0:02 /home/bhzhu/udphop /home/bhzhu/udphp-conf
bhzhu 1512048 0.0 0.0 39936 4160 pts/6 S+ 17:28 0:00 grep --color=auto udp
❰bhzhu❙~❱✔≻ lsof -p 1507979 | wc -l
3208

还有一个疑问,为什么会每秒新增一个1个连接? 不是按照配置里面的80s 才会新增一个连接吗

排查了没多久就发现原来是上次为了解决一个原本不存在的问题(当时我理解错误)搞出了线程死锁

Host not found (authoritative)

看起来是重播的间隙比较大,原先的4次重试、共12秒不够用。现在改成了优先使用缓存着的地址,如果没有缓存再重新解析地址,并且重试时间延长到了30次、每次间隔3秒(共90秒),这样应该就够用

就是这个部分

为了解决各种锁反倒花了大量时间,最后实在眼花,恢复到原本的代码去了。顺便又发现在Linux下有其他线程锁会导致较长时间卡顿,这次也一并解决掉。

在Debian测试了下,看起来是有效果的

$ lsof -p 22484 | wc
23 209 1828

问题还没有解决 刚开始是 1秒新增一个连接 后面就明显加快了:1秒10+连接

❰bhzhu❙~❱✔≻ date ;lsof -p 1528954 |wc
2023年 02月 27日 星期一 13:44:14 CST
24555 221010 1817759
❰bhzhu❙~❱✔≻ date ;lsof -p 1528954 |wc
2023年 02月 27日 星期一 13:44:17 CST
24563 221082 1818351
❰bhzhu❙~❱✔≻ date ;lsof -p 1528954 |wc
2023年 02月 27日 星期一 13:44:21 CST
24571 221154 1818943
❰bhzhu❙~❱✔≻ date ;lsof -p 1528954 |wc
2023年 02月 27日 星期一 13:44:24 CST
24577 221209 1819394

加了个 timeout 选项,还改了下一些处理部分,这回应该有效了

太优秀了 现在连接数基本稳定在29 比较稳定

udp session is stopped
udp session is stopped
udp session is stopped
udp session is stopped
udp session is stopped
udp session is stopped
udp session is stopped
udp session is stopped
udp session is stopped
udp session is stopped
udp session is stopped
udp session is stopped
udp session is stopped
udp session is stopped
udp session is stopped
udp session is stopped
udp session is stopped
udp session is stopped
udp session is stopped
❰bhzhu❙~/source/udphop(git≠main)❱✔≻ lsof -p 1557697 |wc
     29     274    2571
❰bhzhu❙~/source/udphop(git≠main)❱✔≻ lsof -p 1557697 |wc
     29     274    2571
```

现在轮到服务端会自动退出了,运行一段时间会这样

是用alpine系统静态编译的

[32677117.650503] udphop-0228[5361]: segfault at 100000009 ip 000000000049a9b4 sp 00007f9a59357ae8 error 6
[32677117.652107] Code: c7 45 dc 01 00 00 00 e8 5a e8 fe ff 85 c0 0f 95 c0 84 c0 74 1b 48 8b 45 e8 48 89 45 f0 8b 45 dc 89 45 e0 8b 55 e0 48 8b 45 f0 01 10 90 eb 20 48 8b 45 e8 48 89 45 f8 8b 45 dc 89 45 e4 48 8b

为了方便debug,花了好几天的空闲时间安装桌面环境
不得不说,Alpine这一点真像三大BSD,GUI 同样都要自己手动装

现在 0.7.4 版本在各大系统(指的是 x86-64 的 FreeBSD Linux Windows)应该都是稳定的了

client 现在也会偶尔退出。每天这边晚上19点~20点 "ifconfig eth0 down;echo mem > /sys/power/state" 关闭网卡,使电脑进入挂起状态,第二天9点上班开电脑有时发现udphop进程已经不在了(不频繁,偶尔,是断网的原因引发崩溃?程序是Alpine中静态编译的)

[1013496.738422] udphop[1647204]: segfault at 7ffff7e87ec1 ip 000000000049539b sp 00007fffffffd2f0 error 4 likely on CPU 11 (core 5, socket 0)
[1013496.738445] Code: 89 7d e8 89 75 e4 48 8b 45 e8 48 89 45 f8 8b 45 e4 89 45 f0 8b 45 f0 be ff ff 00 00 89 c7 e8 47 a5 fd ff 89 45 f4 48 8b 45 f8 <0f> b6 00 84 c0 0f 95 c0 c9 c3 90 55 48 89 e5 48 83 ec 20 48 89 7d

服务端就比较频繁了

Segmentation fault
Thu Mar  2 19:26:02 HKT 2023
error_found: No
Servers: 1
Clients: 0
start_up() running in server mode
Segmentation fault
Fri Mar  3 20:08:30 HKT 2023
error_found: No
Servers: 1
Clients: 0
start_up() running in server mode
Segmentation fault
Fri Mar  3 20:38:37 HKT 2023
error_found: No
Servers: 1
Clients: 0
start_up() running in server mode
Segmentation fault
Mon Mar  6 14:48:12 HKT 2023
error_found: No
Servers: 1
Clients: 0
start_up() running in server mode
Segmentation fault
Tue Mar  7 06:10:13 HKT 2023
error_found: No
Servers: 1
Clients: 0
start_up() running in server mode
Segmentation fault
Tue Mar  7 06:40:21 HKT 2023
error_found: No
Servers: 1
Clients: 0
start_up() running in server mode
Segmentation fault
Tue Mar  7 07:10:28 HKT 2023
error_found: No
Servers: 1
Clients: 0
start_up() running in server mode

检查后发现这是迁就我家路由器而导致的问题,原本我的设置是收到 UDP 包后交给另一支 IO 循环去做解包、加解密、转发等操作,这样可以减少我家路由器跑 udphop 的丢包率。想不到这样会造成运行在 Alpine 时直接崩溃。

ASIO 框架的作者对低性能机器跑 kqueue + 大压力数据包排队的情况应该没怎么测试过(我猜其实是在各大 BSD 都没怎么测试过,顶多测了下 FreeBSD,在 NetBSD 环境竟然连 IPv4 映射地址都无法解析)。只用一支 IO 循环一把梭的话,会在我的路由器出现比较“严重”的抖动和丢包的情况,同机转发数据量跑到500Mbps时丢包率1%~2%(iperf 的结果),只有300Mbps以下时才不会丢包。
开启两路 IO 循环能够稍稍减轻丢包率(一半左右)。从实际使用的角度来看,其实这时的1%和0.5%的区别真不大,我只是“强迫症”觉得这样丢包真不应该。

现在我改回了最初期的做法,收到数据包就立即做解包、加解密、转发等操作,不交给另一支 IO 循环。这个做法对于 Windows 和 Linux 来说都是性能最佳并且最稳妥的。至于我家路由器,其实 udphop 内的数据量基本不可能跑到 100Mbps 以上,想了想也没必要为了几百Mbps时零点几的丢包率斤斤计较。

顺便可以提一提,最初的时候我还打算在 Linux 环境下指定 ASIO 框架调用 io_uring,没多久就发现框架的作者对于 liburing 的使用似乎不太熟练(准确来说是各个网络框架的作者对 io_uring 都不熟练),调用 io_uring 的性能反倒不如 epoll,速度总是低一点。最后就只好放弃这个想法。

最近不是min'gan时期嘛,发现基于UDP多端口的技术已经可以被识别,好像是直接对服务器的UDP进行断流.UDPHOP连不上服务器会有相应输出吗

最近不是min'gan时期嘛,发现基于UDP多端口的技术已经可以被识别,好像是直接对服务器的UDP进行断流.UDPHOP连不上服务器会有相应输出吗

检查了一下 是上一个版本的服务端udphop意外退出了 导致客户端连不上。

[234286.579723] udphop[1372]: segfault at 7ffff7fb0da8 ip 0000000000496f5e sp 00007ffff7fdbd60 error 4 likely on CPU 1 (core 1, socket 0)
[234286.579751] Code: fe ff 48 8b 45 f8 48 83 c0 08 48 89 c7 e8 90 1f fe ff 90 c9 c3 90 55 48 89 e5 48 83 ec 10 48 89 7d f8 48 89 75 f0 48 8b 45 f0 <48> 8b 10 48 8b 45 f8 48 89 10 48 8b 45 f8 48 83 c0 08 48 8b 55 f0
```
今天客户端报错退出了一次,虽然现在已经比较稳定了

再次感谢反馈,在Windows和Linux各自跟踪了几天,发现原来是上次改的时候删错一处代码了
它能坚持两个星期不崩溃真是奇迹

而我自己用的时候每天都关机,没能立即复现