C/S程序的一般流程和基本socket函數(七)

一、基於TCP協議的網絡程序



服務器調用socket()、bind()、listen()完成初始化後,調用accept()阻塞等待,處於監聽端口的狀態,客戶端調用socket()初始化後,調用connect()發出SYN段並阻塞等待服務器應答,服務器應答一個SYN-ACK段,客戶端收到後從connect()返回,同時應答一個ACK段,服務器收到後從accept()返回。


數據傳輸的過程:

建立連接後,TCP協議提供全雙工的通信服務,但是一般的客戶端/服務器程序的流程是由客戶端主動發起請求,服務器被動處理請求,一問一答的方式。因此,服務器從accept()返回後立刻調用read(),讀socket就像讀管道一樣,如果沒有數據到達就阻塞等待,這時客戶端調用write()發送請求給服務器,服務器收到後從read()返回,對客戶端的請求進行處理,在此期間客戶端調用read()阻塞等待服務器的應答,服務器調用write()將處理結果發回給客戶端,再次調用read()阻塞等待下一條請求,客戶端收到後從read()返回,發送下一條請求,如此循環下去。


如果客戶端沒有更多的請求了,就調用close()關閉連接,就像寫端關閉的管道一樣,服務器的read()返回0,這樣服務器就知道客戶端關閉了連接,也調用close()關閉連接。注意,任何一方調用close()後,連接的兩個傳輸方向都關閉,不能再發送數據了。如果一方調用shutdown()則連接處於半關閉狀態,仍可接收對方發來的數據。


在學習socket API時要注意應用程序和TCP協議層是如何交互的: 

*應用程序調用某個socket函數時TCP協議層完成什麼動作,比如調用connect()會發出SYN段

 *應用程序如何知道TCP協議層的狀態變化,比如從某個阻塞的socket函數返回就表明TCP協議收到了某些段,再比如read()返回0就表明收到了FIN段


補充一下,其實TCP 共有11種狀態,上圖沒有出現的CLOSING 狀態,當雙方同時關閉連接時會出現此狀態,替換掉FIN_WAIT2狀態。

有機狀態圖:
圖中有三種不同的箭頭。粗實線箭頭表示對客戶進程的正常變遷。粗虛線箭頭表示對服務器進程的正常變遷。另一種細線箭頭表示異常變遷。




需要注意: TCP 連接必須經過時間 2MSL 後才真正釋放掉。因爲:爲了保證 A(客戶) 發送的最後一個 ACK 報文段能夠到達 B(服務器);防止“已失效的連接請求報文段”出現在本連接中。A 在發送完最後一個 ACK 報文段後,再經過時間 2MSL(時間等待計時器),就可以使本連接持續的時間內所產生的所有報文段,都從網絡中消失。這樣就可以使下一個新的連接中不會出現這種舊的連接請求報文段。


二、基本socket函數

1、socket函數

包含頭文件<sys/socket.h>
功能:創建一個套接字用於通信
原型:int socket(int domain, int type, int protocol);
參數
domain :指定通信協議族(protocol family),AF_INET、AF_INET6、AF_UNIX等
type:指定socket類型,流式套接字SOCK_STREAM,數據報套接字SOCK_DGRAM,原始套接字SOCK_RAW
protocol :協議類型,IPPROTO_TCP等;一般由前兩個參數就決定了協議類型,設置爲0即可。
返回值:成功返回非負整數, 它與文件描述符類似,我們把它稱爲套接口描述字,簡稱套接字。失敗返回-1


2、bind函數

包含頭文件<sys/socket.h>
功能:綁定一個本地地址到套接字
原型:int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
參數
sockfd:socket函數返回的套接字
addr:要綁定的地址
addrlen:地址長度
返回值:成功返回0,失敗返回-1



3、listen函數

包含頭文件<sys/socket.h>
功能:將套接字用於監聽進入的連接
原型:int listen(int sockfd, int backlog);
參數
sockfd:socket函數返回的套接字
backlog:已完成三次握手的最大連接個數
返回值:成功返回0,失敗返回-1

一般來說,listen函數應該在調用socket和bind函數之後,調用函數accept之前調用。
對於給定的監聽套接口,內核要維護兩個隊列:
1、已由客戶發出併到達服務器,服務器正在等待完成相應的TCP三路握手過程
2、已完成連接的隊列



4、accept函數

包含頭文件<sys/socket.h>
功能:從已完成連接隊列返回第一個連接,如果已完成連接隊列爲空,則阻塞。
原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
參數
sockfd:服務器套接字
addr:將返回對等方的套接字地址
addrlen:返回對等方的套接字地址長度
返回值:成功返回非負整數,失敗返回-1


5、connect函數

包含頭文件<sys/socket.h>
功能:建立一個連接至addr所指定的套接字
原型:int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
參數
sockfd:未連接套接字
addr:要連接的套接字地址
addrlen:第二個參數addr長度
返回值:成功返回0,失敗返回-1






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