從socket api看網絡通信流程

 戳藍字「TopCoder」關注我們哦!

說了網絡通信,大家肯定都不會陌生,比如各種分佈式系統、大數據框架等等都要涉及到網絡通信,由於大多數通信都是基於TCP協議來的,因此本文就以TCP爲例,結合socket api來分析Linux下的網絡通信流程。

TCP協議是基於IP協議之上的面向流並且可靠傳輸的通信協議,同時TCP也擁有流量控制和擁塞控制機制。說起TCP,就繞不開的TCP的3次握手和4次揮手,因此先看下握手和揮手流程:

socket api

常用的網絡通信socket api有socket、bind、listen、accept和connect等。

爲了進行網絡通信,進程需要首先調用socket函數獲取一個socket fd,可以指定通信協議類型:

// family指定協議族,type指定套接字類型,protocol指定某個協議類型常值,或者設爲0。
int socket(int family, int type, int protocol);

bind函數把一個本地協議地址賦予一個套接字,至於協議地址的含義則取決於協議本身,對於TCP,調用bind函數可以指定一個端口號。

int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen); // 返回:成功爲0,出錯-1

bind函數綁定特定的IP地址必須屬於其所在主機的網絡接口之一,服務器在啓動時綁定它們衆所周知的端口,如果一個TCP客戶端或服務端未曾調用bind綁定一個端口,當調用connect或listen時,內核就要爲響應的套接字選擇一個臨時端口。讓內核選擇臨時端口對於TCP客戶端來說是正常的,但是對於TCP服務端來說確實罕見的,因爲服務端通過他們衆所周知的端口被大家認識的。

socket創建一個套接字時,它被假設爲一個主動套接字,也就是說,它是一個將調用connect發起連接的一個客戶套接字。listen函數把一個未連接的套接字轉換爲一個被動套接字,指示內核應接受指向該套接字的連接請求,調用listen函數將導致套接字從CLOSEE狀態轉換到LISTEN狀態。

int listen(int sockfd, int backlog); // 返回:成功返回0,出錯-1

backlog表示某個給定套接字上內核爲之排隊的最大已完成連接數,也就是3次握手中已完成隊列的大小。

accept函數由服務器調用,用於從已完成隊列中獲取下一個已完成連接,如果已完成隊列爲空,則進程被投入睡眠(如果該套接字爲阻塞方式的話)。如果accept成功,那麼其返回值是由內核自動生成的一個全新套接字,代表與返回客戶的TCP連接,函數的第一個參數爲監聽套接字,返回值爲已連接套接字。

int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen); //  返回:成功返回已連接描述符(非負),出錯-1

連接建立完成之後就可以進行讀寫操作了,對應read/write等方法。

連接讀寫完成之後就可以進行關閉連接操作了,close一個TCP套接字的默認行爲是把該套接字標記爲已關閉,然後立即返回到調用進程。注意,close實質把該套接字引用值減1,如果該引用值大於0,則對應的套接字不會被真正關掉。

int close(int sockfd); // 若成功返回0,出錯-1

close時的詳細的4次揮手流程如下:

 推薦閱讀 


歡迎小夥伴關注【TopCoder】閱讀更多精彩好文。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章