




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、做linux下的網絡編程有一段時間了,中間遇到過很多問題,其中不少是因為自己對網絡編程和網絡協議的一些基本概念搞不清楚,趁著今天沒心情干活就把自己在網絡編程方面的理解和一些經驗總結一下,Request For Comments。在諸多的網絡協議中接觸的最多也最緊密的無疑是TCP和UDP,SCTP之前因為項目原因也研究過,不過最終由于方案修改給拋棄了,TCP年代已經很久遠,在網上的資料也非常多,而且我感覺它是一種非常復雜的協議,感覺要把編好基于TCP的程序光簡單地了解幾個socket API是不夠的,剛開始接觸網絡編程的時候自己確實也吃了不少苦頭,后來我還專門拿時間出來閱讀了一下RFC,再加上長
2、時間的實踐總算也對TCP有所了解,把自己的一些經驗和教訓都總結一下。首先說一下TCP的狀態轉移圖,這個應該是很重要的,了解TCP運行周期的各種狀態才能更好地運用netstat之類的應用程序去對程序進行調試,我這里收藏了一張圖,是TCP的狀態圖,記不清是從哪里找來的,也不知道直接版權該給誰,但這張圖應該最終是出自于UNP第一卷的,那copyright就是UNP了吧。1.TCP連接狀態連接建立的幾個狀態沒什么可說的,TCP的三次握手眾所周知,更重要的是TCP連接中止的幾個狀態,應該可以說是連接中止需要四次握手吧。當Client調用close函數主動關閉socket時,連接狀態被標記為FIN_WAI
3、T_1,Server在收到FIN之后read函數會返回0,這里server知道Client已經關閉連接,回復ACK,這里client連接狀態被標記為FIN_WAIT_2,接下來Server調用close函數關閉連接,這時候Server向client發送FIN,Client收到之后將狀態標記為TIME_WAIT,并回復ACK。TIME_WAIT這個狀態存在的意義在于Client回復的ACK未必會被Server收到,可能在傳輸過程中導致包的丟失,而這里Server未收到ACK之后會重新向Client發送FIN,如果client未將狀態標記為TIME_WAIT而是直接標記為CLOSED,則Serve
4、r發送的FIN會直接收到RST,導致Server端的發送錯誤,因此Client需要保證有一個TIME_WAIT狀態,而這個狀態會持續兩位的MSL(最大段生命周期),從而保證Server成功發送FIN并發送ACK,為了保證兩個數據段傳輸的最大時間,因此TIME_WAIT持續的時間為兩倍的MSL。Server在收到第一個FIN之后會將狀態標記為CLOSE_WAIT,此時是client主動關閉連接,這里Server也需要調用Close給Client發送FIN(如上所述),之后Server的狀態標記為LAST_ACK,表示Server正在等待Client發送的最后一個ACK,當Server收到最后一個
5、ACK便會將連接標記為CLOSED,這時連接結束。TIME_WAIT這個狀態和套接字的SO_REUSEADDR選項是有關系的,這個留做后面討論。2.TCP連接異常情況TCP連接異常分為很多種情況,無論是客戶端程序還是服務器端程序都需要考慮周全的。Server在連接的過程中程序崩潰或者CTRL+C中止程序,或者kill接Server進程。這時會導致Server立即發送一個FIN數據包給Client,Client如果此時正在調用recv函數,則recv函數返回0,表示服務器已關閉連接,如果Client調用send函數繼續向Server發送數據,Server在收到后會回復RST,而此時send方法會
6、觸發SIGPIPE信號,表示通信管道已斷開,在程序中如果對該信號不做處理則會導致程序的崩潰,一般在程序開始時會忽略此信號,則在這種情況下send函數會返回-1,表示發送失敗,處理SIGPIPE的代碼如下:前幾天實驗室這個破項目非要加上什么流媒體的功能,簡單起見使用了VLC來實現,客戶端這邊就得需要把相關的播放界面整合到現有的界面里面來,之前的客戶端UI我都是用GTK實現的,沒辦法,GTK用得比較多,相對熟練一些就用GTK來做了,沒想到要把VLC整到GTK里面來那么麻煩,原生的libvlc是不支持GTK的,需要加一層libvlc-gtk,從網上好不容易下載到了libvlc-gtk的源碼,從哪里下
7、的也記不清了,反正就是零散地幾個文件,沒有README甚至連Makefile都沒有,沒辦法首先得先寫個Makefile把它編譯一下,libvlc-gtk一共有八個文件,Makefile如下:struct sigaction sa;sa.sa_handler = SIG_IGN;sigaction(SIGPIPE, &sa, 0 );另外在這種情況下select函數也會立即返回,socket描述符會被設置,而試圖從該socket中recv數據,則會返回-1。另外一種情況是Server系統崩潰或者網絡直接異常或斷開,這時候Server不可能再給Client發送FIN包,而Client調用s
8、end函數后會導致數據包一直重傳直接超時后返回-1,而recv函數也會一直阻塞直接超時后返回-1。這種情況就很難判斷是Server端進程關閉還是網絡異常,這種情況一般會用TCP的KEEP ALIVE機制,每隔一定的時間向對方發送一個只有一字節數據內容的數據包,對端收到后會返回一個ACK,以此來確保連接正常,如果未收到ACK,會嘗試重傳,直到重試規定次數后可以將與對端的連接標記為斷開,send和recv將會返回-1。KEEP ALIVE的使用方法如下:int tcp_keep_alive(int socketfd)int keepAlive = 1;int keepIdle = 10; /* 開
9、始發送KEEP ALIVE數據包之前經歷的時間 */int keepInterval = 10; /* KEEP ALIVE數據包之前間隔的時間 */int keepCount = 10; /* 重試的最大次數 */ if(setsockopt(socketfd , SOL_SOCKET , SO_KEEPALIVE,(void*)&keepAlive,sizeof(keepAlive) = -1)debug_info("set SO_KEEPALIVE failedn");return -1; if(setsockopt(socketfd ,
10、SOL_TCP , TCP_KEEPIDLE,(void *)&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; i
11、f(setsockopt(socketfd , SOL_TCP , TCP_KEEPCNT,(void *)&keepCount,sizeof(keepCount) = -1)debug_info("set TCP_KEEPCNT failedn");return -1;return 1;上面這個函數只針對Linux,昨天有網友告知在Mac OS上TCP_KEEPIDLE ,TCP_KEEPINTVL, TCP_KEEPCNT這些宏將未定義。另外對于這些參數的設置也是需要注意的,很多系統中它們的設置并不是對單個socket描述符起作用的,而是該機器上的所有socke
12、t描述符起作用的,所以這個需要注意(這個是從UNP里面看到的)。3.關于字節順序Linux的主機字節順序是采用little-endian字節順序,而網絡字節順序是采用big-endian字節順序,字節順序轉換是必需的。寫了一個小程序來檢測字節順序,不知道對不對,Request For Comment.#include int main(int argc, char *argv)short s = 0x0102;if(*(unsigned char*)&s) = 2)printf("little endiann");else if(*(unsigned c
13、har*)&s) = 1)printf("big endiann");elseprintf("unknown endiann"); return 0;3.關于send和recv寫過socket程序的人肯定都會知道send和recv函數并不會總是返回要求發送或讀取的字節數,如:int ret = recv(sk, buf, 2096, 0);這句話并不總是讀取到完整地2096個字節,相反地,大多數情況下都不能將buf讀滿,recv只能返回當前可以讀取到的字節數,如果協議規定本次讀取肯定會讀取到N個字節,那我一般的做法會寫一個這樣的函數來確
14、保讀取到固定的字節數: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, len-n, flags) != -1 &&ret; n += ret);return (n!=len)? -1:n;關于這兩個函數還有很重要的一點是應該盡可能大地一次發送或接收更多地數據,當然前提是緩沖區中有這些數據的話,原因很簡單,當通信鏈路很好的時候數據可能會填滿系統緩沖區,而r
15、ecv便是從緩沖區中讀取數據,這時候一次讀取更多地字節就意味著可以少調用幾次recv函數,而這些函數通常都是調用了系統調用,需要進行內核態和用戶態上下文的切換,也就意味著多調用幾次recv會帶來額外的開銷,之前寫的一個代理服務器的程序數據傳輸速度一直很低,后來修改了recv和send的緩沖區大小后速率提高了近一倍。4.關于非阻塞模式一般應用的時候都是使用阻塞式IO,至少我在大多數情況下都用的阻塞式IO,非阻塞很少應用,但存在便我價值,我用到的非阻塞IO的情況一般是用來進行超時connect,首先將socket設為非阻塞模式,connect立即返回-1,此時已向對端發送FIN,而并未來得及收到任
16、何ACK,于是直接返回-1,但并不代表連接失敗,errno會被置為EINPROGRESS ,表示連接正在進行中,然后通過select來設置socket可寫的超時時間,如果規定時間內可寫,且socket并無出錯,則表示連接成功,socket出錯則表示連接失敗,或規定時間內不可寫則表示連接超時,簡單地寫了如下代碼:#include#include#include#include#include#include#include int main(int argc, char *argv)int sk;int flags;int err = 0;int ret;socklen_t len;
17、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) = -1 )perror("fcntl GET flags failed");return 1; if(fcntl(sk, F_SETFL, flags | O_NONBLOCK) = -1
18、) 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*)&addr, sizeof(addr) = -1) if(errno != EINPROGRESS)
19、 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
20、, SO_ERROR, &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;el
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 中國屠宰后鮮肉項目創業計劃書
- 中國急救輸液泵項目創業計劃書
- 中國傘花木屬項目創業計劃書
- 中國克氏原螯蝦項目創業計劃書
- 中國觀光農業園項目創業計劃書
- 2025餐廳轉讓合同標準版范本
- 2025個人貸款合同范本
- 中國尿石癥管理裝置項目創業計劃書
- 中國電阻網絡項目創業計劃書
- 中國多媒體移動通信系統項目創業計劃書
- 《熔焊方法及設備》第二版思考題(課后)
- 活髓保存治療蓋髓術的概述
- GB/T 26832-2011無損檢測儀器鋼絲繩電磁檢測儀技術條件
- 世界現代設計史-課件
- 第十三講:外交與領事關系法課件
- 神經生物物理學課件
- 10000中國普通人名大全
- T∕CWAN 0033-2021 鋁合金攪拌摩擦焊體積型缺陷相控陣超聲檢測規范
- 報廢機動車拆解有限公司應急預案
- 基于微信小程序的連連看小游戲的設計與實現
- 國際汽車貿易檢驗、檢疫、索賠、仲裁與不可抗力
評論
0/150
提交評論