1. 程式人生 > >Linux學習之網路程式設計(TCP程式設計 模型總結)

Linux學習之網路程式設計(TCP程式設計 模型總結)

言之者無罪,聞之者足以戒。 - “詩序”

TCP通訊也就是伺服器和客戶端的一種通訊方式,它的整體框架為:

針對TCP通訊所用到的函式,我來做一下說明:

(1)插座創造一個套接字

int socket(int domain,int type,int protocol)

標頭檔案的:#include <SYS / socket.h>中

第一個引數:通訊域,確定通訊特性,包括地址格式域描述

第二個引數:套接字型別

第三個引數:指定相應的傳輸協議

返回值:成功則返回套接字檔案描述符,失敗返回-1

引數域:通訊域,確定通訊特性,包括地址格式域描述
引數協議:指定相應的傳輸協議,也就是諸如TCP或UDP協議等等,系統針對每一個協議簇與型別提供了一個預設的協議,我們通過把協議設定為0來使用這個預設的值。

family:     type:       組合      AF_INET AF_INET6 AF_LOCAL AF_PACKET
解釋     SOCK_STREAM 位元組   流套接字   TCP TCP YES  
AF_INET IPv4協議   SOCK_DGRAM 資料包套接字   UDP UDP YES  
AF_INET6 IPv6協議   SOCK_RAM 原始套接字   IPv4 IPv6   ethernet
AF_LOCAL/AF_UNIX 本地套接字                
AF_PACKET                  

(2)建立與TCP伺服器的連線 

int   connect(int sockfd, const  struct  sockaddr  *servaddr, socklen_t  addrlen)

第一個引數:是由socket函式返回的套接字描述符

第二個引數:指向套接字地址結構的指標

第三個引數:地址結構的大小

套接字地址結構必須包含有伺服器的IP地址和埠號

返回值:成功返回0,出錯返回-1

客戶在呼叫connect之前不必非得呼叫bind函式,因為如果需要的話,核心會確定源IP地址並選擇一個臨時埠作為埠號

如果是TCP套接字,呼叫connect函式將激發TCP的三次握手過程,而且僅在連線建立成功或出錯時才返回,其中,出錯返回的可能情況有以下幾種:

1)若TCP客戶沒有收到SYN分節的響應,則返回ETIMEDOUT錯誤。舉例,呼叫connect函式時,4.4BSD核心傳送一個SYN,若無響應則等待6s後再發送一個,若仍無響應則等待24s後再發送一個。若總共等待了75s後仍未收到響應則返回本錯誤

2)若對客戶的SYN的響應是RST(表示復位),則表明該伺服器主機在我們指定的埠上沒有程序在等待與之連線。這是一種硬錯誤,客戶一收到RST就馬上返回ECONNREFUSED錯誤。

3)若客戶發出的SYN在中間的某個路由器上引發了一個“destination unreachable”(目的地不可達)ICMP錯誤,則認為是一個軟錯誤。客戶主機核心儲存該訊息,並按第一種情況所述的時間間隔繼續傳送SYN。若在某個規定的時間內仍無響應,則把儲存的資訊(即ICMP錯誤)作為EHOSTUNREACH或ENETUNREACH錯誤返回給程序。以下兩種情況是有可能的:一是按照本地系統的轉發表,根本沒有到達遠端系統的路徑;二是connect呼叫根本不等待就返回。

(3)結合繫結伺服器的地址和埠到插座

這樣做就是讓客戶端來發現用以連線的伺服器的地址

int bind(int sockfd,const struct sockaddr * addr,socklen_t len)

標頭檔案:#include <sys / socket.h>

第一個引數:是由socket函式返回的套接字描述符

第二個引數:伺服器的地址

第三個引數:地址的長度

返回值:成功返回0,失敗返回-1
引數地址:伺服器的地址,對於因特網域,如果設定地址為INADDR_ANY,套接字可以繫結到所有的網路埠。這意味著可以收到這個系統所有網絡卡的資料包。一般我們,在使用SOCKADDR_IN型別的結構體代替的sockaddr行業釋義體系結構
引數len:指定地址的長度

下面羅列一下常見的幾種出錯情況:

1)IP地址可以選擇通配地址,埠號為0表示(核心分配臨時埠)

2)INADDR_ANY,由核心選擇IP介面,這個巨集的值為0(注意:該巨集對於IPv4是可行的)

3)分配臨時埠號,需要用函式getsockname,來返回 你的協議地址

4)繫結通常會返回的錯誤:Address  already  in  use ,通過套接字選項來設定,setsockopt,SO_REUSEADDR

(4)設定允許的最大連線數

int listen(int sockfd,int backlog)

標頭檔案:#include <sys / socket.h>

第一個引數:是由socket函式返回的套接字描述符

第二個引數:用於表示伺服器能接受的請求數量

返回值:成功返回0,失敗返回-1

伺服器呼叫監聽函式來宣告可以接受連線請求

關於listen函式的相關內容可以參考https://www.cnblogs.com/lengender-12/p/6813057.html

(5)接受等待來自客戶端的連線請求

int accept(int sockfd,struct sockaddr * restrict addr,socklen_t * restrict len)

標頭檔案的:#include <SYS / socket.h>中

第一個引數:是由socket函式返回的套接字描述符

第二個引數:用來存放客戶端的地址,如果地址的空間足夠大,系統會自動填充。

第三個引數:地址的長度

返回值:成功則返回套接字描述符,失敗返回-1

一旦伺服器呼叫了聽,套接字就能接收連線請求。使用接受函式來接受並建立請求

 注意:
1,接受返回一個新的socket關聯到客戶端,它與原始的socket有相同的套接字型別和協議族。傳遞給接受的原始socket並沒有關聯客戶端,它要繼續保持可用狀態,接收其他請求。
2,接受是一個阻塞的函式,會一直等到有客戶端的請求。