Linux 隨記
Tcp鏈接關閉
在linux中,一切皆文件,本身socket就是一種文件類型,內核會為每一個打開的文件創建file結構并維護指向改結構的引用計數,每一個進程結構中都會維護本進程打開的文件數組,數組下標就是fd,內容就指向上面的file結構,close本身就可以用來操作所有的文件,做的事就是,刪除本進程打開的文件數組中指定的fd項,并把指向的file結構中的引用計數減一,等引用計數為0的時候,就會調用內部包含的文件操作close,針對于socket,它內部的實現應該就是調用shutdown,只是參數是關閉讀寫端,從而比較粗暴的關閉連接。
第二個問題,信號的處理有三種,默認處理,忽略處理,自定義處理。默認處理就是采用系統自定義的操作,大部分信號的默認處理都是殺死進程,忽略處理就是當做什么都沒有發生。
tw_reuse和SO_REUSEADDR區別
tcp_tw_reuse 是內核選項,主要用在連接的發起方。TIME_WAIT 狀態的連接創建時間超過 1 秒后,新的連接才可以被復用,注意,這里是連接的發起方;
SO_REUSEADDR 是用戶態的選項,SO_REUSEADDR 選項用來告訴操作系統內核,如果端口已被占用,但是 TCP 連接狀態位于 TIME_WAIT ,可以重用端口。如果端口忙,而 TCP 處于其他狀態,重用端口時依舊得到“Address already in use”的錯誤信息。注意,這里一般都是連接的服務方。
Linux中TCP報文重傳
net.ipv4.tcp_syn_retries = 6
net.ipv4.tcp_synack_retries = 5
對于SYN報文,重傳時間由上面兩個內核參數控制
tcp_syn_retries Total_time = 2^0 + 2^1…+2^6=2^7-1=127s
net.ipv4.tcp_synack_retries = 2^6-1=63s
案例1:最常見的內核參數調優就是為了防止DoS(拒絕服務攻擊)和DDoS(分布式拒絕服務攻擊)。其中SYN Flood是當前最流行的DoS與DDoS的方式之一,這是一種利用TCP協議缺陷,發送大量偽造的TCP連接請求,常用假冒的IP或IP號段發來的海量請求連接的第一個握手包(SYN包),被攻擊服務器回應第二個握手包(SYN+ACK包),因為對方是假冒IP,對方永遠收不到包且不會回應第三個握手包。導致被攻擊服務器保持大量SYN_RECV狀態的“半連接”,并且會重試默認5次回應第二個握手包,塞滿TCP等待連接隊列,資源耗盡(CPU滿負荷或內存不足),讓正常的業務請求連接不進來。
-
開啟syncookies后,當SYN隊列滿了后,TCP會通過原地址端口,目的地址端口和時間戳打造一個特別的Sequence Number(又叫cookie發回去,如果是攻擊者則不會有響應,如果是正常連接則把這個SYNCookie發回來,然后服務器端可以通過cookie建立連接(即使不在SYN隊列)。
案例2:在ha1.5版本的時候,由于還不支持熱重載機制,當ha的配置文件變更時,一個臨時的解決辦法是通過開啟SO_REUSEPORT,在ha reload過程中服務端直接拒絕所有的syn連接請求(比如通過iptables drop掉指定端口80的所有syn包),這樣client端會根據上述內核參數在一定時間后重新發送syn請求,當服務端ha reload完成時,再允許syn連接
net.ipv4.tcp_retries1
net.ipv4.tcp_retries2
快速重傳
快速重傳機制「RFC5681」基于接收端的反饋信息來引發重傳,而非重傳計時器超時。
剛剛提到過,基于計時器的重傳往往要等待很長時間,而快速重傳使用了很巧妙的方法來解決這個問題:服務器如果收到亂序的包,也給客戶端回復 ACK,只不過是重復的 ACK。就拿剛剛的例子來說,收到亂序的包 6,7,8,9 時,服務器全都發 ACK = 5。這樣,客戶端就知道 5 發生了空缺。一般來說,如果客戶端連續三次收到重復的 ACK,就會重傳對應包,而不需要等到計時器超時。
TCP用戶超時UTO
可以在通過setsockopt來設置TCP用戶超時時長,表示:已發出的數據包若在指定的時間沒有被確認,則關閉連接,相當于單次的tcp_keepalive
需要注意的是該值會影響tcp報文重傳機制中的RTO時間和待發送隊列數據的最大保存時間
在netstat中查看各種鏈接狀態的計時器
通過-o選項,查看Timer,如下

keepalive (6176.47/0/0)
<1st field> <2nd field>
該 1st field 可以有價值:
keepalive - 當套接字的keepalive定時器為ON時
on - 當套接字的重傳定時器為ON時
tme wait - 主動斷開連接的一方所處的tw狀態2MSL計時器 ,linux一般為30 * 2s
off - 以上都不是ON
該 2nd field 有三個子字段:
(6176.47/0/0) -> (a/b/c)
a =定時器值(a = keepalive定時器,當1st field =“keepalive”時; a =重傳定時器,當1st field =“on”時)
b =已發生的重新傳輸次數
c =已發送的keepalive探測器的數量
Linux IO多路復用
為什么select/poll/epoll等IO多路復用一般不搭配阻塞IO:https://www.zhihu.com/question/37271342
SIGPIPE信號理解
在netfilet中注冊一個hook handler:
Linux中的進程描述符
一個連接對應一個socket,每個socket都有獨立的緩沖區(內核緩沖區):套接字也是文件,當server端監聽到有連接時,應用程序會請求內核創建Socket,Socket創建好后會返回一個文件描述符給應用程序,當有數據包過來網卡時,內核會通過數據包的源端口,源ip,目的端口等在內核維護的一個ipcb雙向鏈表中找到對應的Socket,并將數據包賦值到該Socket的緩沖區,應用程序請求讀取Socket中的數據時,內核就會將數據拷貝到應用程序的內存空間,從而完成讀取Socket數據

浙公網安備 33010602011771號