unix网络编程——网络基础
一、傳輸控制協(xié)議(TCP)
tcp是面向連接的的,他不可以被描述為100%可靠的協(xié)議,他提供的是數(shù)據(jù)的可靠傳遞或故障的可通知。它保證了數(shù)據(jù)的可以順序到達、不重復(fù)、不丟包。tcp重要的是三次握手和四次揮手做了什么,每次響應(yīng)和發(fā)送都代表了什么。基本的TCP編程模板如下圖:
?
1.1 三次握手階段
SYN:表同步。
服務(wù)器端:執(zhí)行socket創(chuàng)建監(jiān)聽套接字,使用bind函數(shù)來綁定存有端口與IP地址的結(jié)構(gòu)體到socket,執(zhí)行listen函數(shù)使服務(wù)端主動連接的socket轉(zhuǎn)化為被動的socket,使這個socket可以等待其他socket的連接請求,再利用accpt函數(shù)從連接隊列中取出連接請求,這里并不是建立了連接,如果連接隊列為空的話服務(wù)端進入睡眠,如果執(zhí)行成功的話返回一個非零的描述符用作后續(xù)信息傳輸?shù)亩丝?#xff08;已連接套接字)。
客戶端:執(zhí)行socket創(chuàng)建套接字,使用connect函數(shù)連接服務(wù)端,這里是主動打開。
三次握手的過程:
1、服務(wù)器執(zhí)行了accpt后進入等待客戶端接入的狀態(tài),此時是被動打開,而客戶端調(diào)用connect后主動連接服務(wù)器,執(zhí)行connect后進入阻塞狀態(tài)(SYN_SENT),并且發(fā)送SYN包。
2、服務(wù)端收到客戶端發(fā)送的SYN包后進入SYN_RECV狀態(tài)并且回應(yīng)客戶端的SYN包,回應(yīng)的是一個ACK包,他就是客戶端SYN包加一,且發(fā)送一個自己的SYN包。
3、客戶端接受到服務(wù)器的響應(yīng)和服務(wù)器發(fā)送的SYN包進入數(shù)據(jù)傳輸狀態(tài)(ESTABLISH),發(fā)送ACK響應(yīng)包,內(nèi)容就是服務(wù)器發(fā)送的SYN包加一。
4、服務(wù)器再接收到這個ACK包后也進入數(shù)據(jù)傳輸狀態(tài)(ESTABLISH)。此時accpt返回一個已連接套接字,就可以開始通訊了。
1.2 數(shù)據(jù)傳輸階段
1.客戶端使用write來進行數(shù)據(jù)請求。
2.服務(wù)器使用read得到客戶端的請求,再使用write返回客戶端需要的數(shù)據(jù)和請求ACK包。
3.客戶端使用read讀取服務(wù)端返回的數(shù)據(jù)并且給服務(wù)器發(fā)送一個應(yīng)答ACK包。
注意點:有序列號所以不會重復(fù)發(fā)送,也不會亂序,更不會導(dǎo)致漏發(fā)。
具有流量控制,TCP總是告知對端他能夠接受到多少字節(jié)的數(shù)據(jù),不會導(dǎo)致接受緩沖區(qū)溢出。
1.3 四次揮手階段
1.客戶端調(diào)用close函數(shù)主動關(guān)閉,進入FIN_WAIT_1階段并發(fā)送FIN包。
2.服務(wù)端接受FIN包后進入CLOSE_WAIT狀態(tài),并返回一個ACK包(FIN+1)。
3.客戶端接受到ACK包后進入FIN_WAIT_2狀態(tài)。
4.服務(wù)端調(diào)用close函數(shù)進入LAST_ACK狀態(tài)并發(fā)送一個FIN包。
5.客戶端接收到FIN包后進入TIME_WAIT狀態(tài),并返回ACK包。
6.服務(wù)端接收到ACK后進入CLOSED狀態(tài),關(guān)閉連接。
整個過程如下圖所示:
二、TIME_WAIT狀態(tài)
TIME_WAIT狀態(tài)是客戶端發(fā)送ACK包后的狀態(tài),此時他不會直接關(guān)閉,因為他發(fā)送的ACK包有可能在傳輸?shù)倪^程中丟掉了,并不會被服務(wù)端所接受到,服務(wù)端有可能重新發(fā)送FIN包,如果客戶端直接關(guān)閉會導(dǎo)致服務(wù)端一直反復(fù)發(fā)送FIN包等待結(jié)束。所以需要有TIME_WAIT這一狀態(tài),這個狀態(tài)持續(xù)的時間為2MSL(MSL:任何IP包在intel網(wǎng)中存活的最長時間)。
所以TIME_WAIT的存在可以使TCP執(zhí)行完整的關(guān)閉,允許老的重復(fù)的分節(jié)在網(wǎng)絡(luò)中消逝。
三、常用結(jié)構(gòu)體
struct sockaddr{unsigned short sa_family;//地址類型AF_xxxxchar sa_data[14];//14字節(jié),2字節(jié)端口號,剩余放IP }; struct sockaddr_in{short int sin_family;//地址類型AF_xxxxunsigned short int sin_port;//2字節(jié)端口號struct in_addr sin_addr;//存IP地址的結(jié)構(gòu)體unsigned char sin_zero[8];//占位,保持與sockaddr結(jié)構(gòu)體占一樣內(nèi)存大小 }; struct in_addr{unsigned long s_addr;//4字節(jié)存放IP地址 };sockaddr_in比sockaddr結(jié)構(gòu)體好就好在IP和端口分開存儲。?
四、recv與send的本質(zhì)
應(yīng)用層函數(shù)recv、send與內(nèi)核中套接字的真正讀取數(shù)據(jù),TCP協(xié)議層是運行在內(nèi)核中的,二通信是網(wǎng)卡直接通訊,只要對方send,線路上就有數(shù)據(jù),那么協(xié)議就會從網(wǎng)卡讀取數(shù)據(jù)進入內(nèi)核的socket緩沖區(qū)中,recv只是從socket內(nèi)核中把數(shù)據(jù)拷貝到指定的緩沖區(qū)buf中,對協(xié)議毫無影響。
socket默認(rèn)是全緩沖,如果沒有setsocketopt的話,只有當(dāng)socket內(nèi)核緩沖區(qū)中的數(shù)據(jù)滿了才會發(fā)送,通過網(wǎng)卡發(fā)送。send其實就是將應(yīng)用層數(shù)據(jù)拷貝到socket的緩沖區(qū)而已,并不代表真正的數(shù)據(jù)發(fā)送。
五、主機與網(wǎng)絡(luò)字節(jié)序(大小端問題)
主機字節(jié)序:小端存儲,數(shù)據(jù)的高位存放在終止地址,數(shù)據(jù)的低位存放在起始地址。
網(wǎng)絡(luò)字節(jié)序:大端存儲,數(shù)據(jù)的高位存放在起始地址,數(shù)據(jù)的低位存放在終止地址。
在網(wǎng)絡(luò)的傳輸中需要利用兩種字節(jié)序的轉(zhuǎn)換函數(shù)來進行轉(zhuǎn)換,這些函數(shù)可以自己找找看。我們也可以寫個函數(shù)來判斷系統(tǒng)是大端還是小端,代碼如下:
int main(int arv,char** argv) {union{short s;char c[sizeof(short)]}un;un.s=0x0102;printf("%s:",CPU_OS);if(sizeof(short)==2){if(un.c[0]==1&&un.c[1]==2){printf("big-endian\n");}else printf("little-endian\n");} exit(0); }?
總結(jié)
以上是生活随笔為你收集整理的unix网络编程——网络基础的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ukey功能适配文档
- 下一篇: 去掉IE里的Alexa工具条(转)