最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

一文詳解TCP/IP協(xié)議棧的心跳、丟包重傳、連接超時機制實例

2023-09-15 14:52 作者:補給站Linux內(nèi)核  | 我要投稿

1、問題概述

雖然軟件底層模塊在網(wǎng)絡(luò)恢復(fù)后能自動重連上服務(wù)器,但會議因為網(wǎng)絡(luò)問題已經(jīng)退出,需要重新加入會議。因為客戶特殊的網(wǎng)絡(luò)運行環(huán)境,會頻繁出現(xiàn)網(wǎng)絡(luò)抖動不穩(wěn)定的情況,客戶要求必須要實現(xiàn)60秒內(nèi)網(wǎng)絡(luò)恢復(fù)后能依然保持在會議中,保證會議流程不被中斷。

客戶堅持要實現(xiàn)這個特殊的功能點,項目已經(jīng)接近尾聲,目前處于客戶試用階段,不實現(xiàn)該功能,項目無法通過驗收,客戶不給錢。

前方同事將當(dāng)前問題及項目進展情況向研發(fā)部門領(lǐng)導(dǎo)反饋,研發(fā)部緊急召開討論會議,商討60秒不掉會的實現(xiàn)方案。這里面涉及到兩大類的網(wǎng)絡(luò)連接,一類是傳輸控制信令的TCP連接,另一類是傳輸音視頻碼流的UDP連接。UDP連接的問題不大,主要是TCP連接的斷鏈與重連問題,下面主要討論TCP連接相關(guān)問題。

在出現(xiàn)網(wǎng)絡(luò)不穩(wěn)定掉會時,可能是系統(tǒng)TCPIP協(xié)議棧已經(jīng)檢測到網(wǎng)絡(luò)異常,系統(tǒng)協(xié)議層已經(jīng)將網(wǎng)絡(luò)斷開了;也可能軟件應(yīng)用層的心跳機制檢測到網(wǎng)絡(luò)故障,斷開了與服務(wù)器的鏈接。對于系統(tǒng)TCPIP協(xié)議棧自身檢測出來的網(wǎng)絡(luò)異常,則可能存在兩種情況,一是TCPIP協(xié)議棧自身的心跳機制檢測出來的;二是TCP連接的丟包重傳機制檢測出異常。

對于應(yīng)用層的心跳檢測機制,我們可以放大超時檢測時間。本文我們主要討論一下TCPIP協(xié)議棧的TCP連接的心跳、丟包重傳、連接超時等機制。在檢測到網(wǎng)絡(luò)異常后,我們底層可以自動發(fā)起重連或者信令發(fā)送觸發(fā)自動重連,業(yè)務(wù)模塊將會議相關(guān)資源保存不釋放,在網(wǎng)絡(luò)恢復(fù)后可以繼續(xù)保持在會議中,可以繼續(xù)接收到會議中的音視頻碼流,可以繼續(xù)進行會議中的一些操作!

2、TCPIP協(xié)議棧的心跳機制

2.1、TCP中的ACK機制

TCP建鏈時的三次握手流程如下所示:


之所以說TCP連接是可靠的,首先是發(fā)送數(shù)據(jù)前要建立連接,再就是收到數(shù)據(jù)后都會給對方恢復(fù)一個ACK包,表明我收到你的數(shù)據(jù)包了。對于數(shù)據(jù)發(fā)送端,如果數(shù)據(jù)發(fā)出去后沒有收到ACK包,則會觸發(fā)丟包重傳機制。不管是建鏈時,還是建鏈后的數(shù)據(jù)收發(fā)時,都有ACK包,TCP/IP協(xié)議棧的心跳包也不例外。

2.2、TCPIP協(xié)議棧的心跳機制說明

TCP/IP協(xié)議棧有個默認(rèn)的TCP心跳機制,這個心跳機制是和socket套接字(TCP套接字)綁定的,可以對指定的套接字開啟協(xié)議棧的心跳檢測機制。默認(rèn)情況下,協(xié)議棧的心跳機制對socket套接字是關(guān)閉的,如果要使用需要人為開啟的。在Windows中,默認(rèn)是每隔2個小時發(fā)一次心跳包,客戶端程序?qū)⑿奶l(fā)給服務(wù)器后,接下來會有兩種情況:

1)網(wǎng)絡(luò)正常時:服務(wù)器收到心跳包,會立即回復(fù)ACK包,客戶端收到ACK包后,再等2個小時發(fā)送下一個心跳包。其中,心跳包發(fā)送時間間隔時間keepalivetime,Windows系統(tǒng)中默認(rèn)是2小時,可配置。如果在2個小時的時間間隔內(nèi),客戶端和服務(wù)器有數(shù)據(jù)交互,客戶端會收到服務(wù)器的ACK包,也算作心跳機制的心跳包,2個小時的時間間隔會重新計時。2)網(wǎng)絡(luò)異常時:服務(wù)器收不到客戶端發(fā)過去的心跳包,沒法回復(fù)ACK,Windows系統(tǒng)中默認(rèn)的是1秒超時,1秒后會重發(fā)心跳包。如果還收不到心跳包的ACK,則1秒后重發(fā)心跳包,如果始終收不到心跳包,則在發(fā)出10個心跳包就達到了系統(tǒng)的上限,就認(rèn)為網(wǎng)絡(luò)出故障了,協(xié)議棧就會直接將連接斷開了。其中,發(fā)出心跳包收不到ACK的超時時間稱為 keepaliveinterval,Windows系統(tǒng)中默認(rèn)是1秒,可配置;收不到心跳包對應(yīng)的ACK包的重發(fā)次數(shù)probe,Windows系統(tǒng)是固定的,是固定的10次,不可配置的。

所以TCP/IP協(xié)議棧的心跳機制也能檢測出網(wǎng)絡(luò)異常,不過在默認(rèn)配置下可能需要很久才能檢測出來,除非網(wǎng)絡(luò)異常出現(xiàn)在正在發(fā)送心跳包后等待對端的回應(yīng)時,這種情況下如果多次重發(fā)心跳包都收不到ACK回應(yīng),協(xié)議棧就會判斷網(wǎng)絡(luò)出故障,主動將連接關(guān)閉掉。

2.3、修改TCP/IP協(xié)議棧的默認(rèn)心跳參數(shù)

TCP/IP協(xié)議棧的默認(rèn)心跳機制的開啟,不是給系統(tǒng)整個協(xié)議棧開啟心跳監(jiān)測,而是對某個socket套接字開啟。開啟心跳機制后,還可以修改心跳的時間參數(shù)。從代碼上看,先調(diào)用setsockopt給目標(biāo)套接字開啟心跳監(jiān)測機制,再調(diào)用WSAIoctl去修改心跳檢測的默認(rèn)時間參數(shù),相關(guān)代碼如下所示:

上面的代碼可以看到,先調(diào)用setsockopt函數(shù),傳入SO_KEEPALIVE參數(shù),打開TCP連接的心跳開關(guān),此時心跳參數(shù)使用系統(tǒng)默認(rèn)的心跳參數(shù)值。緊接著,調(diào)用WSAIoCtrl函數(shù),傳入SIO_KEEPALIVE_VALS參數(shù),同時將設(shè)置好時間值的心跳參數(shù)結(jié)構(gòu)體傳進去。下面對心跳參數(shù)結(jié)構(gòu)體tcp_keepalive做個詳細的說明:(以Windows系統(tǒng)為例)

1)keepalivetime:默認(rèn)2小時發(fā)送一次心跳保活包,比如發(fā)送第1個?;畎螅g隔2個小時后再發(fā)起下一個?;畎?。如果這期間有數(shù)據(jù)交互,也算是有效的?;畎?,這個時間段就不再發(fā)送?;畎?,發(fā)送下個?;畎臅r間間隔會從收發(fā)的最后一條數(shù)據(jù)的時刻開始重新從0計時。2)keepaliveinterval:發(fā)送保活包后,沒有收到對端的ack的超時時間默認(rèn)為1秒。假設(shè)和對端的網(wǎng)絡(luò)出問題了,給對端發(fā)送第1個?;畎?秒內(nèi)沒有收到對端的ack,則發(fā)第2個?;畎?秒內(nèi)沒有收到對端的?;畎?,再發(fā)送下一個?;畎?,.....,直到發(fā)送第10個?;畎?,1秒鐘還沒收到ack回應(yīng),則達到發(fā)送10次?;畎奶綔y次數(shù)上限,則認(rèn)為網(wǎng)絡(luò)出問題了。3)probe探測次數(shù):Windows系統(tǒng)上的探測次數(shù)被固定為10次,不可修改。

MSDN上對心跳機制檢測出的網(wǎng)絡(luò)異常的說明如下:

If a connection is dropped as the result of keep-alives the error code WSAENETRESET is returned to any calls in progress on the socket, and any subsequent calls will fail with WSAENOTCONN.

因為?;畲螖?shù)達到上限導(dǎo)致連接被丟棄掉,所有正在調(diào)用中的套接字接口會返回WSAENETRESET錯誤碼,后續(xù)的套接字api函數(shù)的調(diào)用都會返回WSAENOTCONN。


【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【749907784】整理了一些個人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。。ê曨l教程、電子書、實戰(zhàn)項目及代碼)? ? ??


3、libwebsockets開源庫中的心跳機制使用的就是TCPIP協(xié)議棧的心跳機制

我們的產(chǎn)品之前在使用websocket時,就遇到?jīng)]有設(shè)置心跳機制導(dǎo)致TCP長連接被網(wǎng)絡(luò)設(shè)備無故釋放的問題。我們客戶端程序在登錄時,會去連接某業(yè)務(wù)的注冊服務(wù)器,建立的是websocket長連接。這個長連接一直保持著,只有使用該業(yè)務(wù)模塊的業(yè)務(wù)時才會使用到該連接,在該連接上進行數(shù)據(jù)交互。軟件登錄后,如果一直沒有操作該業(yè)務(wù)模塊的業(yè)務(wù),這個長連接會一直處于閑置狀態(tài),即這個連接上沒有數(shù)據(jù)交互。結(jié)果在某次測試過程中出現(xiàn)了問題,排查下來發(fā)現(xiàn),這個長連接因為長時間沒有數(shù)據(jù)交互,被中間的網(wǎng)絡(luò)設(shè)備關(guān)閉了。后來為了解決這個問題,我們在初始化websocket庫時設(shè)置心跳參數(shù),這樣上述websocket長連接在空閑的時候能跑一跑心跳包,這樣就能確保該長連接不會因為長時間沒有跑數(shù)據(jù)被無故關(guān)閉的問題了。我們在調(diào)用lws_create_context接口創(chuàng)建websockets會話上下文時,該接口的結(jié)構(gòu)體參數(shù)lws_context_creation_info中,有設(shè)置心跳參數(shù)的字段:

其中的ka_time、ka_probes和ka_interval三個字段就是心跳相關(guān)的設(shè)置參數(shù)。我們初始化websockets上下文的代碼如下:

通過查閱libwebsockets開源庫代碼得知,此處設(shè)置的心跳使用的就是TCPIP協(xié)議棧的心跳機制,如下所示:

4、TCPIP丟包重傳機制

如果網(wǎng)絡(luò)出故障時,客戶端與服務(wù)器之間正在進行TCP數(shù)據(jù)交互,客戶端給服務(wù)器發(fā)送數(shù)據(jù)包后因為網(wǎng)絡(luò)故障收不到服務(wù)器的ACK包,就會觸發(fā)客戶端的TCP丟包重傳,丟包重傳機制也能判斷出網(wǎng)絡(luò)出現(xiàn)異常。對于TCP連接,客戶端給服務(wù)器發(fā)送數(shù)據(jù)后沒有收到服務(wù)器的ACK包,會觸發(fā)丟包重傳。每次重傳的時間間隔會加倍,當(dāng)重傳次數(shù)達到系統(tǒng)上限(Windows默認(rèn)的上限是5次,Linux默認(rèn)的上限是15次)后,協(xié)議棧就認(rèn)為網(wǎng)絡(luò)出故障了,會直接將對應(yīng)的連接關(guān)閉了。? ? ? ? ?所以當(dāng)網(wǎng)絡(luò)出現(xiàn)故障時有數(shù)據(jù)交互,協(xié)議棧會在數(shù)十秒內(nèi)檢測到網(wǎng)路出現(xiàn)異常,就會直接將連接直接關(guān)閉掉。丟包重傳機制的詳細描述如下所示:



對于丟包重傳機制,可以通過給PC插拔網(wǎng)線來查看,可以使用wireshark抓包看一下。快速插拔網(wǎng)線時(先拔掉網(wǎng)線,等待幾秒鐘再將網(wǎng)線插上),給服務(wù)器發(fā)送的操作指令會因為丟包重傳會收到數(shù)據(jù)的。

5、使用非阻塞socket和select接口實現(xiàn)connect連接的超時控制

5.1、MSDN上對connect和select接口的說明

對于tcp套接字,我們需要調(diào)用套接字函數(shù)connect去建立TCP連接。我們先來看看微軟MSDN上對套接字接口connect的描述:


On a blocking socket, the return value indicates success or failure of the connection attempt.

對于阻塞式的socket,通過connect的返回值就能確定有沒有連接成功,返回0表示連接成功。

對于非組賽式的socket,connect調(diào)用會立即返回,但連接操作還沒有完成。connect返回SOCKET_ERROR,對于非阻塞式socket,返回SOCKET_ERROR并不表示失敗,需要調(diào)用WSAGetLastError獲取connect函數(shù)執(zhí)行后的LastError值,一般此時WSAGetLastError會返回WSAEWOULDBLOCK:



表明連接正在進行中。可以使用select接口檢測一下套接字是否可寫(套接字是否在writefds集合中),如果可寫,則表示連接成功。如果套接字在exceptfds集合中,則說明連接出現(xiàn)了異常,如下所示:


5.2、使用非阻塞socket和select實現(xiàn)連接超時的控制

對于阻塞式的socket,在Windows下,如果遠端的IP和Port不可達,則會阻塞75s后返回SOCKET_ERROR,表明連接失敗。所以當(dāng)我們測試遠端的IP和Port是否可以連接時,我們不使用阻塞式的socket,而是使用非阻塞式socket,然后調(diào)用select,通過select添加連接超時時間,實現(xiàn)連接超時的控制。

select函數(shù)因為超時返回,會返回0;如果發(fā)生錯誤,則返回SOCKET_ERROR,所以判斷時要判斷select返回值,如果小于等于0,則是連接失敗,立即將套接字關(guān)閉掉。如果select返回值大于0,則該返回值是已經(jīng)準(zhǔn)備就緒的socket個數(shù),比如連接成功的socket。我們判斷套接字是否在可寫集合writefds中,如果在該集合中,則表示連接成功。

根據(jù)MSDN上的相關(guān)描述,我們就能大概知道該如何實現(xiàn)connect的超時控制了,相關(guān)代碼如下:






一文詳解TCP/IP協(xié)議棧的心跳、丟包重傳、連接超時機制實例的評論 (共 條)

分享到微博請遵守國家法律
霍城县| 炎陵县| 鲁甸县| 固原市| 涞水县| 绵竹市| 南乐县| 汾西县| 元江| 西吉县| 通化县| 肇源县| 合江县| 合肥市| 宜黄县| 东平县| 蒙城县| 西城区| 澜沧| 巴塘县| 大荔县| 都兰县| 绥宁县| 望都县| 石景山区| 修文县| 祥云县| 图们市| 元谋县| 神池县| 汝城县| 百色市| 和政县| 杭锦后旗| 中卫市| 隆化县| 深水埗区| 拜泉县| 龙江县| 西宁市| 松江区|