日常記錄 - 5.3
拔掉網(wǎng)線后,原本的TCP 連接還存在嗎?
拔掉網(wǎng)線后,有數(shù)據(jù)傳輸
如果超過(guò)重傳的閾值(tcp_retries2
),才接入網(wǎng)線,則對(duì)端會(huì)把TCP 連接斷開。
此時(shí)等客戶端插回網(wǎng)線后,如果還向服務(wù)端發(fā)送了數(shù)據(jù),由于服務(wù)端已經(jīng)沒有與客戶端相同四元組的TCP 連接了,因此服務(wù)端會(huì)回復(fù)RST 報(bào)文,客戶端收到后就會(huì)釋放該TCP 連接。
若是在超時(shí)時(shí)間內(nèi)把網(wǎng)線插回,則無(wú)事發(fā)生。
為什么tcp_tw_reuse 默認(rèn)是關(guān)閉的?
開啟了tcp_tw_reuse的同時(shí)也需要開啟時(shí)間戳功能。
RST 報(bào)文的時(shí)間戳即使過(guò)期了,只要RST 報(bào)文的序列號(hào)在對(duì)方的接收窗口內(nèi),也是能被接受的。
存在風(fēng)險(xiǎn):快速?gòu)?fù)用TIME_WAIT 狀態(tài)的端口,導(dǎo)致新連接可能被回繞序列號(hào)的RST 報(bào)文斷開了。如果保留2MSL時(shí)長(zhǎng),那么這個(gè)RST 報(bào)文就會(huì)自然消亡。
如果第四次揮手的ACK丟失,此時(shí)被復(fù)用了可能導(dǎo)致處于LAST_ACK 狀態(tài)的服務(wù)端收到這個(gè)復(fù)用重連的SYN 報(bào)文后,會(huì)回復(fù)Challenage ACK,并不是確認(rèn)收到SYN 報(bào)文。 處于 SYN_SENT 狀態(tài)的客戶端收到服務(wù)端的Challenage ACK后,發(fā)現(xiàn)不是期待收到的確認(rèn)號(hào),于是回復(fù)RST 報(bào)文,服務(wù)端收到后,斷開連接。
HTTPS 中 TLS 和TCP 能同時(shí)握手嗎?
「HTTPS 中的 TLS 握手過(guò)程可以同時(shí)進(jìn)行三次握手」,需要下面這兩個(gè)條件同時(shí)滿足才可以:
客戶端和服務(wù)端都開啟了 TCP Fast Open 功能,且 TLS 版本是 1.3;
客戶端和服務(wù)端已經(jīng)完成過(guò)一次通信;
QUIC
Packet Header 細(xì)分這兩種:
Long Packet Header 用于首次建立連接。
Short Packet Header 用于日常傳輸數(shù)據(jù)。
Short Packet Header 中的 Packet Number 是每個(gè)報(bào)文獨(dú)一無(wú)二的編號(hào),它是嚴(yán)格遞增的,也就是說(shuō)就算 Packet N 丟失了,重傳的 Packet N 的 Packet Number 已經(jīng)不是 N,而是一個(gè)比 N 大的值。 這樣的設(shè)計(jì)可以分辨是否是重傳報(bào)文。
QUIC Frame Header
QUIC 通過(guò)單向遞增的 Packet Number,配合 Stream ID 與 Offset 字段信息,可以支持亂序確認(rèn)而不影響數(shù)據(jù)包的正確組裝,擺脫了TCP 必須按順序確認(rèn)應(yīng)答 ACK 的限制,解決了 TCP 因某個(gè)數(shù)據(jù)包重傳而阻塞后續(xù)所有待發(fā)送數(shù)據(jù)包的問(wèn)題。
這個(gè)設(shè)計(jì)也解決了隊(duì)頭阻塞的問(wèn)題。
QUIC的流量控制
QUIC 實(shí)現(xiàn)了兩種級(jí)別的流量控制,分別為 Stream 和 Connection 兩種級(jí)別:
Stream 級(jí)別的流量控制:Stream 可以認(rèn)為就是一條 HTTP 請(qǐng)求,每個(gè) Stream 都有獨(dú)立的滑動(dòng)窗口,所以每個(gè) Stream 都可以做流量控制,防止單個(gè) Stream 消耗連接(Connection)的全部接收緩沖。
Connection 流量控制:限制連接中所有 Stream 相加起來(lái)的總字節(jié)數(shù),防止發(fā)送方超過(guò)連接的緩沖容量。
多個(gè)TCP 服務(wù)可以綁定同一個(gè)端口嗎?
如果兩個(gè) TCP 服務(wù)進(jìn)程同時(shí)綁定的 IP 地址和端口都相同,那么執(zhí)行 bind() 時(shí)候就會(huì)出錯(cuò),錯(cuò)誤是“Address already in use”。
在重啟TCP 服務(wù)進(jìn)程時(shí),總會(huì)報(bào)“Address already in use ” ?
這是因?yàn)橹貑⒑?,服?wù)端發(fā)起了關(guān)閉連接的操作,經(jīng)歷了四次揮手,處于TIME_WAIT 狀態(tài)。
如何避免?
調(diào)用 bind 前,對(duì) socket 設(shè)置 SO_REUSEADDR 屬性,可以解決這個(gè)問(wèn)題。
客戶端是在調(diào)用 connect 函數(shù)的時(shí)候,由內(nèi)核隨機(jī)選取一個(gè)端口作為連接的端口。
而如果我們想自己指定連接的端口,就可以用 bind 函數(shù)來(lái)實(shí)現(xiàn):客戶端先通過(guò) bind 函數(shù)綁定一個(gè)端口,然后調(diào)用 connect 函數(shù)就會(huì)跳過(guò)端口選擇的過(guò)程了,轉(zhuǎn)而使用 bind 時(shí)確定的端口。
服務(wù)端沒有l(wèi)isten,客戶端發(fā)起連接建立,會(huì)發(fā)生什么?
如果服務(wù)端只bind(),而沒有l(wèi)isten ,如果客戶端對(duì)服務(wù)端發(fā)起了連接建立,服務(wù)端會(huì)回復(fù)RST 報(bào)文。
沒有l(wèi)isten,能建立TCP 連接嗎?
可以??蛻舳丝梢孕纬蒚CP 自連接,即兩個(gè)客戶端同時(shí)向?qū)Ψ桨l(fā)出請(qǐng)求,建立連接。
客戶端會(huì)有半連接隊(duì)列嗎?
沒有,半連接隊(duì)列和全連接隊(duì)列都是在執(zhí)行l(wèi)isten 方法時(shí),內(nèi)核自動(dòng)創(chuàng)建的。但內(nèi)核還有個(gè)全局 hash 表,可以用來(lái)存放socket 連接的信息。
在 TCP 自連接的情況中,客戶端在 connect 方法時(shí),最后會(huì)將自己的連接信息放入到這個(gè)全局 hash 表中,然后將信息發(fā)出,消息在經(jīng)過(guò)回環(huán)地址重新回到 TCP 傳輸層的時(shí)候,就會(huì)根據(jù) IP + 端口信息,再一次從這個(gè)全局 hash 中取出信息。于是握手包一來(lái)一回,最后成功建立連接。
TCP 同時(shí)打開的情況也類似。
用了TCP 協(xié)議,數(shù)據(jù)一定不會(huì)丟失嗎?
建立連接時(shí)丟包:半連接隊(duì)列或者全連接隊(duì)列滿了。
流量控制丟包:所有數(shù)據(jù)一股腦沖入網(wǎng)卡,網(wǎng)卡會(huì)吃不消;發(fā)送數(shù)據(jù)過(guò)快,流控隊(duì)列txqueuelen 又不夠大時(shí),就容易出現(xiàn)丟包現(xiàn)象。
網(wǎng)卡丟包:RingBuffer過(guò)小導(dǎo)致丟包。在接收數(shù)據(jù)時(shí),會(huì)將數(shù)據(jù)暫存到RingBuffer接收緩沖區(qū)中,然后等著內(nèi)核觸發(fā)軟中斷把數(shù)據(jù)收走。如果這個(gè)緩沖區(qū)不夠大,就會(huì)出現(xiàn)丟包情況。
兩端網(wǎng)絡(luò)之間的丟包
mtr命令可以查看是哪個(gè)節(jié)點(diǎn)丟包。 ?例如: mtr -r baidu.com ?-r 是指report,以報(bào)告形式打印結(jié)果
有些host顯示的是??? ,是因?yàn)閙tr默認(rèn)用的ICMP包,某些節(jié)點(diǎn)對(duì)ICMP包進(jìn)行了限制,所以不能顯示。