網絡上的兩個程序經過一個雙向的通訊鏈接實現數據的交換,這個鏈接的一端稱爲一個socket。程序員
說明:socket是應用層與傳輸層之間的一個抽象層,它把TCP/IP複雜的操做抽象爲幾個簡單的接口供應用層調用。web
創建鏈接須要一對socket,其中一個運行於客戶端,稱爲ClientSocket,一個運行服務端,稱爲ServerSocket。編程
服務端說明:服務端經過調用bind()把指定IP地址和端口號進行綁定後,經過調用listen()函數使socket進入被動監聽狀態(一開始建立socket都是主動狀態,listen()做用就是使服務端socket從主動鏈接狀態變爲被動鏈接狀態),內核會建立SYN隊列以及Accept隊列,其中Accept隊列的長度是由listen()函數中的backlog參數進行指定的,而後能夠經過調用accept()函數接收客戶端請求,在調用了accept()函數後,默認是阻塞進程的,直到有一個客戶端請求鏈接,鏈接成功後返回一個新的socket描述符,此後,服務器端便可使用這個新的socket描述符與該客戶端進行通訊了,而舊的socket描述符則繼續用於監聽其餘客戶端的鏈接請求。bash
客戶端說明:客戶端經過調用connect()鏈接指定服務端socket時,將會發起一個鏈接請求的同步序列編號(SYN:是TCP/IP創建鏈接時的握手信號),服務器端在接收到客戶端發送過來的鏈接請求的時候會將請求方放進SYN隊列裏,而且給客戶端回覆一個ACK+SYN,這稱爲第二次握手,客戶端在收到ACK+SYN以後,connect將返回,併發送確認鏈接幀ACK給服務器端,這是第三次握手,服務端收到ACK幀後,會將請求方從SYN隊列中移出,放入到Accept隊列中,而accept也等到了本身的資源,從阻塞中喚醒,從Accept中取出請求方,從新創建並返回一個新的socket描述符。服務器
socket緩衝區(阻塞模式)網絡
socket被建立後,都會被分配兩個緩衝區,輸入緩衝區和輸出緩衝區。
數據結構
輸入緩衝區:數據的讀取都是從輸入緩衝區中進行讀取的。併發
輸出緩衝區:數據的寫入都是寫入到輸出緩衝區中。socket
write()/send()並不會馬上向網絡中傳輸數據,而是將數據寫入到輸出緩衝區,再由TCP協議發送到目標機器,只要數據寫到緩衝區,write()/send()就能夠成功返回,而無論數據有沒有到達目標機器,也無論何時發送數據。這是TCP負責的,不是程序員能夠控制的。函數
(1).當使用write()/send()向緩衝區寫數據的時候,若是輸出緩衝區可用空間比要寫入數據小,則須要分批寫入,write()/send()將被阻塞,須要等到緩衝區數據被髮送到目標機器,騰出空間纔會喚醒write()/send()繼續寫入操做。
(2).若是當前TCP正在向網絡發送數據,輸出緩衝區將會被鎖定,write()/send()也會被阻塞,只有數據發送完成,輸出緩衝區解鎖,write()/send()纔會被喚醒繼續寫入操做。
(3).直到全部數據被寫入輸出緩衝區write()/send()纔會返回。
read()/recv()讀取數據時:
(1).當使用read()/recv()讀取輸入緩衝區數據的時候,若是輸入緩衝區沒有數據,那麼read()/recv()將會被阻塞,直到輸入緩衝區中有數據可用讀取,不然read()/recv()將一直被阻塞。
(2).若是要讀取數據長度小於輸入緩衝區中數據長度,那麼就不能一次性將緩衝區中數據所有讀取完成,剩餘數據將不斷積壓,直到下一次read()/recv()再次讀取。
/**
建立一個socket
int af:指定IP地址類型(經常使用的有AF_INET和AF_INET6)
int type:指定socket類型(經常使用的有SOCK_STREAM和SOCK_DGRAM)
int protocol:表示傳輸協議(經常使用的有IPPROTO_TCP和IPPTOTO_UDP,若是傳入0,則會自動根據第二個參數
,選中合適的協議)
return:成功返回正值 失敗返回-1
*/
int socket( int af, int type, int protocol);複製代碼
/**
用於創建與指定socket的鏈接
int sock:未鏈接socket描述符
struct sockaddr *serv_addr:指向數據結構sockAddr的指針,其中包括目的地端口和IP地址
socklen_t addrlen:爲serv_addr結構體變量大小
return:成功返回0 失敗返回-1
*/
int connect(int sock, struct sockaddr *addr, socklen_t addrlen);複製代碼
/**
服務器經過bind()函數將socket與特定的IP地址和端口綁定起來
int sock:未鏈接socket描述符
struct sockaddr *addr:指向數據結構sockAddr的指針
socklen_t addrlen:爲serv_addr結構體變量大小
return:綁定成功返回0 失敗返回-1
*/
int bind(int sock, struct sockaddr *addr, socklen_t addrlen);
複製代碼
/**
listen()用於讓socket進入被動監聽狀態(剛開始建立的socket都是主動狀態)
int sock:須要進入監聽狀態的socket描述符
int backlog:accept隊列最大長度,若是將backlog的值設置爲SOMAXCONN,就由系統決定accept隊列長度
return 成功返回0 失敗返回-1
*/
int listen(int sock, int backlog);複製代碼
/**
當socket處於監聽狀態時,能夠經過accept()函數接收客戶端請求
int sock:socket描述符
struct sockaddr *addr:這是一個結果參數,它用來接受一個返回值,這返回值指定客戶端地址
socklen_t *addrlen:addrlen 爲參數 addr 的長度
return:返回一個新的socket描述符(此後與對應客戶端進行通訊都是使用這個新的socket)
*/
int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);
複製代碼
/**
向TCP鏈接的另外一端發送數據
int sock:socket描述符
const char FAR *buf:要發送數據的緩衝區
int len:實際要發送數據字節數
int flags:標誌位默認爲0
return:成功返回所發數據字節數
*/
int send( int sock, const char FAR *buf, int len, int flags );
複製代碼
/**
使用recv函數從TCP鏈接的另外一端接收數據。
int sock:socket描述符
char FAR *buf:指明一個緩衝區,該緩衝區用來存放recv函數接收到的數據
int len:指明buf的長度;
int flags:標誌位默認爲0*/
int recv(int sock,char FAR *buf,int len,int flags);複製代碼
借鑑資料: blog.51cto.com/ticktick/77…
終於總結完了,仍是有個別知識點理解得不是很透徹,須要反覆閱讀和理解消化。但願各位小夥伴多多提出寶貴意見,交流學習~