前言
??最近看了一個公眾號推送的文章,說是一個遇到的一個問題—client端連接服務器總是拋出異常,我很喜歡看這樣實戰(zhàn)分享的,因為還沒正式工作,所以很少遇到這樣的情況,解決這樣的問題之后總能加上自己的理解。
??我把來源放在文章最末尾啦!
問題描述
??簡單來講就是client端向server端建立三次連接已經完成,但server的selector沒有響應到這個連接(服務端采用的是selector輪詢機制,疑惑的可以去了解一下nio)
??出問題的時間點會聚集在一起,也就是在某段時間內很頻繁。
問題分析與解決
?在TCP三次握手中,服務端維護了兩個隊列——半連接隊列&&全連接隊列
?我們來回顧一下TCP三次握手的流程:
??1. 首先客戶端發(fā)送syn包,發(fā)送完之后狀態(tài)進入syn_send。
??2. 服務端接受到了syn包,然后發(fā)送syn+ack包,然后把這個連接信息放到半連接隊列中。這時候服務端的狀態(tài)變成syn_rcvd
syn floods 的攻擊就是針對這個來的,每次都只發(fā)送syn包,讓服務端的半連接隊列溢出
??3.客戶端接受到這個包之后給服務端發(fā)送ack包,然后自身的狀態(tài)變成establishied;
??4. 服務端接受到ack包之后,如果全連接池沒滿的話,就從半連接池中取出數(shù)據(jù),放入到全連接池,一個連接就這樣完成了。
??這是理想情況;在第四步的時候,如果全連接池滿了呢?這時候就要看
tcp_abort_on_overflow的指示了,如果是0就暫時不管這個包,丟棄,然后過一段時間給客戶端發(fā)送syn+ack包,相當于重走第二步;如果是1,立刻就給客戶端返回一個消息(reset包),讓它別等了,連接作廢,所以我認為第二種要好一點。
針對上面發(fā)生的問題,我們可以通過
- 設置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中有個參數(shù)BackLog,默認是50,這是來控制隊列大小的,我們可以這樣進行設置
ServerSocket serversocket = new ServerSocket(10000, backlog);
那么怎么能觀察到是否隊列滿了呢?
我們可以使用命令: ss -Int

Recv_Q表示當前隊列中有多少,而Send—Q表示最大是多少,我這個好像是128哎
【參考地址】
?本文參考【阿里技術】,【Hollis】微信公眾號搜索就行了
?https://mp.weixin.qq.com/s/D1sB1WlI-gkN5orVWCvyWg