前言
最近看了一个公众号推送的文章,说是一个遇到的一个问题—client端连接服务器总是抛出异常,我很喜欢看这样实战分享的,因为还没正式工作,所以很少遇到这样的情况,解决这样的问题之后总能加上自己的理解。
我把来源放在文章最末尾啦!
问题描述
简单来讲就是client端向server端建立三次连接已经完成,但server的selector没有响应到这个连接(服务端采用的是selector轮询机制,疑惑的可以去了解一下nio)
出问题的时间点会聚集在一起,也就是在某段时间内很频繁。
问题分析与解决
在TCP三次握手中,服务端维护了两个队列——半连接队列&&全连接队列
我们来回顾一下TCP三次握手的流程:
1. 首先客户端发送syn包,发送完之后状态进入syn_send。
2. 服务端接受到了syn包,然后发送syn+ack包,然后把这个连接信息放到半连接队列中。这时候服务端的状态变成syn_rcvd
syn floods 的攻击就是针对这个来的,每次都只发送syn包,让服务端的半连接队列溢出
3.客户端接受到这个包之后给服务端发送ack包,然后自身的状态变成establishied;
4. 服务端接受到ack包之后,如果全连接池没满的话,就从半连接池中取出数据,放入到全连接池,一个连接就这样完成了。
这是理想情况;在第四步的时候,如果全连接池满了呢?这时候就要看
tcp_abort_on_overflow的指示了,如果是0就暂时不管这个包,丢弃,然后过一段时间给客户端发送syn+ack包,相当于重走第二步;如果是1,立刻就给客户端返回一个消息(reset包),让它别等了,连接作废,所以我认为第二种要好一点。
针对上面发生的问题,我们可以通过
- 设置tcp_abort_on_overflow = 1,来完成
- 或者调整全连接队列的大小
我们可以使用cat /proc/sys/net/ipv4/tcp_abort_on_overflow查看值,好像默认是0,我在腾讯云上试的(这时候我就不得不吐槽一下阿里云了,有个bug,我明明已经学生认证了,买服务器的时候一直要调到学生认证,调到这个界面之后又显示让我不要重复认证,绝望....)
cat /proc/sys/net/ipv4/tcp_abort_on_overflow
那么如何调整全连接队列大小呢?在Socket中有个参数BackLog,默认是50,这是来控制队列大小的,我们可以这样进行设置
ServerSocket serversocket = new ServerSocket(10000, backlog);
那么怎么能观察到是否队列满了呢?
我们可以使用命令: ss -Int
Recv_Q表示当前队列中有多少,而Send—Q表示最大是多少,我这个好像是128哎
【参考地址】
本文参考【阿里技术】,【Hollis】微信公众号搜索就行了
https://mp.weixin.qq.com/s/D1sB1WlI-gkN5orVWCvyWg