knull 发表于 2015-10-13 10:21

tcp经常性reset

使用libuv开发的服务端echoserver测试程序,用go开发的客户端进行测试。在500个链接,不断发送数据的情况下。
会发生大量失败的情况,抓包显示是:echoserver发送了rst消息(tcp层的)。
(分别再用muduo和boost.asio的echoserver进行测试,发现没有链接失败的情况)
下面是失败,其中的两种情况:


请各位大家帮忙研究下啊。

knull 发表于 2015-10-15 21:49

问题找到了:因为listen的时候,backlog这个值设置为了5.以前网络编程书上看到过,默认是5,不过似乎版本太老了。现在查了下,默认值都是128了(sysctl可以查看;SOMAXCON是这个的默认值)。
问题分析:一般情况下,listen会维护两个队列,一个是recv_syn队列(接收到syn);收到syn之后,回复ack,并且发送sync,客户端回复ack之后,会将recv_asyn队列中移动到accept队列中,等待accept系统调用。
            1、分析1.png的情况:recv_syn队列满的情况下,客户端继续发送sync,那么服务端就会直接丢弃;客户端过了一段时间没收到ack,就会重发sync,就会回复rst消息(暂时没找到理论支持)。
               2、分析2.png的情况:已经加入recv_syn队列,并且回复ack和async给客户端;客户端回复了ack,服务收到之后,发现accept队列已经满了,所以将其丢弃,链接已经没了。但是,客户端不知道已经丢弃,于是就发送了第一个数据包。这个时候,服务端就回复一个rst消息,表示该链接已经不存在了。

以上,是我自己的一点分析,不是特别完善。
等各位大侠帮忙分析、补充。
谢谢

knull 发表于 2016-08-29 09:59

上面的解释纯属推断,而且与理论不合,与实际不怎么合。
但是,我网上查了下,有规避方案:
1、本机规避,可以放大队列;可以将tcp_synack_retries设置小;设置tcp_syncookies为1;
2、更好的方法是通过防火墙来过滤这个情况。因为上述情况,可能会被利用引发synFlood,从而造成DOS攻击。

wlmqgzm 发表于 2016-08-29 12:15

本帖最后由 wlmqgzm 于 2016-08-29 12:38 编辑

这个参数值系统默认是128, 还是远远不够用的.因为现在已经进入了单机处理10--100万连接的时代.

目前我的网络层代码已经将这个队列默认增加到200000, 即20万个连接,
一个是目前我的代码可以拒绝DOS, synFlood, 也是RST处理的
因为目前测试linux下CPU全忙状态下, 接入线程被调度的最大延迟为1000毫秒, 连接处理线程有可能没有来得及被调度, 队列就满了,因此, 最极端的情况下, 需要缓存2秒的处理内容,

设置以后, 同时并发16万连接, 单独测试没有出现一个连接丢失.
页: [1]
查看完整版本: tcp经常性reset