一、基於TCP協議的網路程式
下圖是基於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狀態。
二、基本 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