版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、做linux下的網(wǎng)絡(luò)編程有一段時間了,中間遇到過很多問題,其中不少是因為自己對網(wǎng)絡(luò)編程和網(wǎng)絡(luò)協(xié)議的一些基本概念搞不清楚,趁著今天沒心情干活就把自己在網(wǎng)絡(luò)編程方面的理解和一些經(jīng)驗總結(jié)一下,Request For Comments。在諸多的網(wǎng)絡(luò)協(xié)議中接觸的最多也最緊密的無疑是TCP和UDP,SCTP之前因為項目原因也研究過,不過最終由于方案修改給拋棄了,TCP年代已經(jīng)很久遠,在網(wǎng)上的資料也非常多,而且我感覺它是一種非常復(fù)雜的協(xié)議,感覺要把編好基于TCP的程序光簡單地了解幾個socket API是不夠的,剛開始接觸網(wǎng)絡(luò)編程的時候自己確實也吃了不少苦頭,后來我還專門拿時間出來閱讀了一下RFC,再加上長
2、時間的實踐總算也對TCP有所了解,把自己的一些經(jīng)驗和教訓(xùn)都總結(jié)一下。首先說一下TCP的狀態(tài)轉(zhuǎn)移圖,這個應(yīng)該是很重要的,了解TCP運行周期的各種狀態(tài)才能更好地運用netstat之類的應(yīng)用程序去對程序進行調(diào)試,我這里收藏了一張圖,是TCP的狀態(tài)圖,記不清是從哪里找來的,也不知道直接版權(quán)該給誰,但這張圖應(yīng)該最終是出自于UNP第一卷的,那copyright就是UNP了吧。1.TCP連接狀態(tài)1 / 11連接建立的幾個狀態(tài)沒什么可說的,TCP的三次握手眾所周知,更重要的是TCP連接中止的幾個狀態(tài),應(yīng)該可以說是連接中止需要四次握手吧。當(dāng)Client調(diào)用close函數(shù)主動關(guān)閉socket時,連接狀態(tài)被標(biāo)記為F
3、IN_WAIT_1,Server在收到FIN之后read函數(shù)會返回0,這里server知道Client已經(jīng)關(guān)閉連接,回復(fù)ACK,這里client連接狀態(tài)被標(biāo)記為FIN_WAIT_2,接下來Server調(diào)用close函數(shù)關(guān)閉連接,這時候Server向client發(fā)送FIN,Client收到之后將狀態(tài)標(biāo)記為TIME_WAIT,并回復(fù)ACK。TIME_WAIT這個狀態(tài)存在的意義在于Client回復(fù)的ACK未必會被Server收到,可能在傳輸過程中導(dǎo)致包的丟失,而這里Server未收到ACK之后會重新向Client發(fā)送FIN,如果client未將狀態(tài)標(biāo)記為TIME_WAIT而是直接標(biāo)記為CLOSED,
4、則Server發(fā)送的FIN會直接收到RST,導(dǎo)致Server端的發(fā)送錯誤,因此Client需要保證有一個TIME_WAIT狀態(tài),而這個狀態(tài)會持續(xù)兩位的MSL(最大段生命周期),從而保證Server成功發(fā)送FIN并發(fā)送ACK,為了保證兩個數(shù)據(jù)段傳輸?shù)淖畲髸r間,因此TIME_WAIT持續(xù)的時間為兩倍的MSL。Server在收到第一個FIN之后會將狀態(tài)標(biāo)記為CLOSE_WAIT,此時是client主動關(guān)閉連接,這里Server也需要調(diào)用Close給Client發(fā)送FIN(如上所述),之后Server的狀態(tài)標(biāo)記為LAST_ACK,表示Server正在等待Client發(fā)送的最后一個ACK,當(dāng)Server
5、收到最后一個ACK便會將連接標(biāo)記為CLOSED,這時連接結(jié)束。TIME_WAIT這個狀態(tài)和套接字的SO_REUSEADDR選項是有關(guān)系的,這個留做后面討論。2.TCP連接異常情況TCP連接異常分為很多種情況,無論是客戶端程序還是服務(wù)器端程序都需要考慮周全的。Server在連接的過程中程序崩潰或者CTRL+C中止程序,或者kill接Server進程。這時會導(dǎo)致Server立即發(fā)送一個FIN數(shù)據(jù)包給Client,Client如果此時正在調(diào)用recv函數(shù),則recv函數(shù)返回0,表示服務(wù)器已關(guān)閉連接,如果Client調(diào)用send函數(shù)繼續(xù)向Server發(fā)送數(shù)據(jù),Server在收到后會回復(fù)RST,而此時s
6、end方法會觸發(fā)SIGPIPE信號,表示通信管道已斷開,在程序中如果對該信號不做處理則會導(dǎo)致程序的崩潰,一般在程序開始時會忽略此信號,則在這種情況下send函數(shù)會返回-1,表示發(fā)送失敗,處理SIGPIPE的代碼如下:前幾天實驗室這個破項目非要加上什么流媒體的功能,簡單起見使用了VLC來實現(xiàn),客戶端這邊就得需要把相關(guān)的播放界面整合到現(xiàn)有的界面里面來,之前的客戶端UI我都是用GTK實現(xiàn)的,沒辦法,GTK用得比較多,相對熟練一些就用GTK來做了,沒想到要把VLC整到GTK里面來那么麻煩,原生的libvlc是不支持GTK的,需要加一層libvlc-gtk,從網(wǎng)上好不容易下載到了libvlc-gtk的源
7、碼,從哪里下的也記不清了,反正就是零散地幾個文件,沒有README甚至連Makefile都沒有,沒辦法首先得先寫個Makefile把它編譯一下,libvlc-gtk一共有八個文件,Makefile如下:struct sigaction sa;sa.sa_handler = SIG_IGN;sigaction(SIGPIPE, &sa, 0 );另外在這種情況下select函數(shù)也會立即返回,socket描述符會被設(shè)置,而試圖從該socket中recv數(shù)據(jù),則會返回-1。另外一種情況是Server系統(tǒng)崩潰或者網(wǎng)絡(luò)直接異?;驍嚅_,這時候Server不可能再給Client發(fā)送FIN包,而Client調(diào)
8、用send函數(shù)后會導(dǎo)致數(shù)據(jù)包一直重傳直接超時后返回-1,而recv函數(shù)也會一直阻塞直接超時后返回-1。這種情況就很難判斷是Server端進程關(guān)閉還是網(wǎng)絡(luò)異常,這種情況一般會用TCP的KEEP ALIVE機制,每隔一定的時間向?qū)Ψ桨l(fā)送一個只有一字節(jié)數(shù)據(jù)內(nèi)容的數(shù)據(jù)包,對端收到后會返回一個ACK,以此來確保連接正常,如果未收到ACK,會嘗試重傳,直到重試規(guī)定次數(shù)后可以將與對端的連接標(biāo)記為斷開,send和recv將會返回-1。KEEP ALIVE的使用方法如下:int tcp_keep_alive(int socketfd)int keepAlive = 1;int keepIdle = 10; /*
9、 開始發(fā)送KEEP ALIVE數(shù)據(jù)包之前經(jīng)歷的時間 */int keepInterval = 10; /* KEEP ALIVE數(shù)據(jù)包之前間隔的時間 */int keepCount = 10; /* 重試的最大次數(shù) */if(setsockopt(socketfd , SOL_SOCKET , SO_KEEPALIVE,(void*)&keepAlive,sizeof(keepAlive) = -1)debug_info(set SO_KEEPALIVE failedn);return -1;if(setsockopt(socketfd , SOL_TCP , TCP_KEEPIDLE,(vo
10、id *)&keepIdle,sizeof(keepIdle) = -1)debug_info(set TCP_KEEPIDEL failedn);return -1;if(setsockopt(socketfd , SOL_TCP , TCP_KEEPINTVL,(void *)&keepInterval,sizeof(keepInterval) = -1)debug_info(set TCP_KEEPINTVL failedn);return -1;if(setsockopt(socketfd , SOL_TCP , TCP_KEEPCNT,(void *)&keepCount,sizeo
11、f(keepCount) = -1)debug_info(set TCP_KEEPCNT failedn);return -1;return 1;上面這個函數(shù)只針對Linux,昨天有網(wǎng)友告知在Mac OS上TCP_KEEPIDLE ,TCP_KEEPINTVL, TCP_KEEPCNT這些宏將未定義。另外對于這些參數(shù)的設(shè)置也是需要注意的,很多系統(tǒng)中它們的設(shè)置并不是對單個socket描述符起作用的,而是該機器上的所有socket描述符起作用的,所以這個需要注意(這個是從UNP里面看到的)。3.關(guān)于字節(jié)順序Linux的主機字節(jié)順序是采用little-endian字節(jié)順序,而網(wǎng)絡(luò)字節(jié)順序是采用big
12、-endian字節(jié)順序,字節(jié)順序轉(zhuǎn)換是必需的。寫了一個小程序來檢測字節(jié)順序,不知道對不對,Request For Comment.#include int main(int argc, char *argv)short s = 0x0102;if(*(unsigned char*)&s) = 2)printf(little endiann);else if(*(unsigned char*)&s) = 1)printf(big endiann);elseprintf(unknown endiann);return 0;3.關(guān)于send和recv寫過socket程序的人肯定都會知道send和re
13、cv函數(shù)并不會總是返回要求發(fā)送或讀取的字節(jié)數(shù),如:int ret = recv(sk, buf, 2096, 0);這句話并不總是讀取到完整地2096個字節(jié),相反地,大多數(shù)情況下都不能將buf讀滿,recv只能返回當(dāng)前可以讀取到的字節(jié)數(shù),如果協(xié)議規(guī)定本次讀取肯定會讀取到N個字節(jié),那我一般的做法會寫一個這樣的函數(shù)來確保讀取到固定的字節(jié)數(shù):int buf_recv(int sock, void *buf, size_t len, int flags)int n, ret;if(len = 0) return 0;for(n=0;n!=len &(ret = recv(sock, buf+n, le
14、n-n, flags) != -1 &ret; n += ret);return (n!=len)? -1:n;關(guān)于這兩個函數(shù)還有很重要的一點是應(yīng)該盡可能大地一次發(fā)送或接收更多地數(shù)據(jù),當(dāng)然前提是緩沖區(qū)中有這些數(shù)據(jù)的話,原因很簡單,當(dāng)通信鏈路很好的時候數(shù)據(jù)可能會填滿系統(tǒng)緩沖區(qū),而recv便是從緩沖區(qū)中讀取數(shù)據(jù),這時候一次讀取更多地字節(jié)就意味著可以少調(diào)用幾次recv函數(shù),而這些函數(shù)通常都是調(diào)用了系統(tǒng)調(diào)用,需要進行內(nèi)核態(tài)和用戶態(tài)上下文的切換,也就意味著多調(diào)用幾次recv會帶來額外的開銷,之前寫的一個代理服務(wù)器的程序數(shù)據(jù)傳輸速度一直很低,后來修改了recv和send的緩沖區(qū)大小后速率提高了近一倍。4.
15、關(guān)于非阻塞模式一般應(yīng)用的時候都是使用阻塞式IO,至少我在大多數(shù)情況下都用的阻塞式IO,非阻塞很少應(yīng)用,但存在便我價值,我用到的非阻塞IO的情況一般是用來進行超時connect,首先將socket設(shè)為非阻塞模式,connect立即返回-1,此時已向?qū)Χ税l(fā)送FIN,而并未來得及收到任何ACK,于是直接返回-1,但并不代表連接失敗,errno會被置為EINPROGRESS ,表示連接正在進行中,然后通過select來設(shè)置socket可寫的超時時間,如果規(guī)定時間內(nèi)可寫,且socket并無出錯,則表示連接成功,socket出錯則表示連接失敗,或規(guī)定時間內(nèi)不可寫則表示連接超時,簡單地寫了如下代碼:#inc
16、lude#include#include#include#include#include#include int main(int argc, char *argv)int sk;int flags;int err = 0;int ret;socklen_t len;struct sockaddr_in addr;fd_set fd_write;struct timeval tv;if( (sk = socket(AF_INET, SOCK_STREAM, 0) = -1 ) perror(socket);return 1;if( (flags = fcntl(sk, F_GETFL, 0)
17、= -1 )perror(fcntl GET flags failed);return 1;if(fcntl(sk, F_SETFL, flags | O_NONBLOCK) = -1) perror(fcntl SET flags failed);return 1;memset(&addr, 0, sizeof(addr);addr.sin_family = AF_INET;addr.sin_addr.s_addr = inet_addr(59.64.129.169);addr.sin_port = htons(808);if(connect(sk, (struct sockaddr*)&a
18、ddr, sizeof(addr) = -1) if(errno != EINPROGRESS) perror(connect);return 1;FD_ZERO(&fd_write);FD_SET(sk, &fd_write);tv.tv_sec = 5;tv.tv_usec = 0;ret = select(sk + 1, (fd_set*)0, &fd_write, (fd_set*)0, &tv);if(ret 0)if(FD_ISSET(sk, &fd_write) len = sizeof(int);if(getsockopt(sk, SOL_SOCKET, SO_ERROR, &
19、err, &len) = 0) if(err = 0) printf(connect successn); return 0; else fprintf(stderr, connect:%sn, strerror(err); return 1; elsefprintf(stderr, getsockopt:%sn, strerror(err);return 1;elsefprintf(stderr, connect(FD_ISSET) failedn);return 1;else if(ret = 0) fprintf(stderr, connect timeoutn);return 1;else fprintf(std
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 廣東理工學(xué)院《中西跨文化交際》2023-2024學(xué)年第一學(xué)期期末試卷
- 廣東警官學(xué)院《材料化學(xué)實驗B》2023-2024學(xué)年第一學(xué)期期末試卷
- 廣東機電職業(yè)技術(shù)學(xué)院《中學(xué)化學(xué)教學(xué)綜合技能訓(xùn)練》2023-2024學(xué)年第一學(xué)期期末試卷
- 廣東工程職業(yè)技術(shù)學(xué)院《數(shù)字化圖像處理Photoshop》2023-2024學(xué)年第一學(xué)期期末試卷
- 廣東第二師范學(xué)院《建筑施工CAD》2023-2024學(xué)年第一學(xué)期期末試卷
- 廣東財貿(mào)職業(yè)學(xué)院《建筑設(shè)計4》2023-2024學(xué)年第一學(xué)期期末試卷
- 《泌尿系統(tǒng)疾病診治》課件
- 《落落的微笑》課件
- 廣東碧桂園職業(yè)學(xué)院《電視節(jié)目播音主持》2023-2024學(xué)年第一學(xué)期期末試卷
- 廣安職業(yè)技術(shù)學(xué)院《設(shè)計基礎(chǔ)理論》2023-2024學(xué)年第一學(xué)期期末試卷
- 2024年自然資源部北海局所屬事業(yè)單位招聘67人歷年高頻500題難、易錯點模擬試題附帶答案詳解
- 消防改造期間消防應(yīng)急預(yù)案
- 酒精依賴綜合征的護理
- GB/T 44456-2024電子競技場館運營服務(wù)規(guī)范
- 系統(tǒng)工程教案
- DL-T 380-2010接地降阻材料技術(shù)條件
- 限期交貨保證書模板
- 安防設(shè)備更新改造項目可行性研究報告-超長期國債
- 2024過敏性休克搶救指南(2024)課件干貨分享
- 2024年紀(jì)委監(jiān)委招聘筆試必背試題庫500題(含答案)
- 【發(fā)動機曲軸數(shù)控加工工藝過程卡片的設(shè)計7800字(論文)】
評論
0/150
提交評論