Socket 編程的層次模型以下圖所示,ios
最上面是應用層,應用層下面的是 SOCKET API 層,再下面是傳輸層和網絡層…… 實際上, Sockets API 層並非一個真正定義的網絡層次,但卻很好的描述了 Socket 編程所處的位置和所扮演的角色。編程
TCP 狀態轉換圖服務器
簡單的, Socket 能夠被定義描述爲兩個應用通訊通道的端點。一個Socket 端點能夠用 Socket 地址來描述, Socket 地址結構由 IP 地址,端口和使用協議組成( TCP or UDP )。網絡
網絡中以主機 IP 、端口以及使用的協議代表一個網絡應用。UNIX Socket 將它們組成一個結構,統稱爲 SOCKET 地址結構。socket
一般也稱爲「網際 SOCKET 地址結構」,以「 socketaddr_in 」命名,定義在頭文件 <netinet/in.h> 中。函數
所涉及到的數據類型:學習
當地址結構做爲傳遞給任何一個 SOCKET 函數的參數時,任意一個Socket 函數必須能處理每一種地址結構,爲了解決這個問題,提出了使用通用套接口地址結構。當任何一個地址結構要做爲指針參數傳到套接口函數時,必需要顯示轉化爲通用地址結構。spa
在 IPv4 應用中,使用的通用地址結構爲 struct sockaddr, 定義在<sys/socket.h> 中,設計
例如:3d
在 IPv6 中,提出了一種新的通用地址結構: struct sockaddr_storage 定義在<netinet/in.h>中。
struct sockaddr 和 struct sockaddr_storage 的區別
<!--[if !supportLists]-->a.<!--[endif]-->struct sockaddr_storage能提供嚴格的結構對齊
<!--[if !supportLists]-->b. <!--[endif]-->struct sockaddr_storage能容納系統支持的更大的地址結構
Client/Server 的網絡通訊模型是使用最廣最爲基礎的通訊模型。在Socket API 環境,其應用能夠概括爲:
TCP 連接創建
根據 TCP/IP 協議,函數 connect() 激發 TCP 的三路握手過程。
客戶端給服務器一個 SYN(J) 信號,服務器返回一個 ACK(J+1); 而後服務器給客戶端一個 SYN(K), 客戶端也一樣給服務器一個 ACK(K+1),這樣就算 connect 成功。
注意:服務器返回的 SYN(K) 和 ACK(J+1) 是放在同一個分節中發給客戶端的,所以鏈路在創建鏈接時只用了三個分節,故稱爲三路握手。
TCP 連接終止
TCP 用三個分節創建一個連接,而終止鏈接時須要四個分節。緣由在於被動關閉連接一方須要關閉處理時間,所以 ACK 和 FIN 不能同時發給主動關閉一方。
主動關閉一方在收到 ACK 後,在等待被動關閉方發 FIN 消息這一狀態稱爲處於 TIME_WAIT 狀態。
應用程序在使用套接字前,必須擁有一個套接字,系統調用 socket()嚮應用程序提供
建立套接字的手段,其調用格式以下:
參數 family 指定通訊發生的區域, UNIX 系統支持的地址族有:AF_UNIX,AF_INET,AF_NS 等,而 DOS 、 WINDOWS 中僅支持 AF_INET ,它是網際網區域。所以,地址族與協議族相同。
參數 type 描述要創建的套接字的類型。參數 protocol 說明該套接字使用的特定協議,若是調用者不但願特別指定使用的協議,則置爲 0 ,使用默認的鏈接模式。根據這 3個參數創建一個套接字,並將相應的資源分配給它,同時返回一個整型套接字號。所以,socket ()系統調用實際上指定了 " 協議 " 。
一個套接字用 socket ()建立後,存在一個名字空間(地址族),但它沒有被命名。 Bind ()將套接字地址(包括本地主機地址和本斷口地址)與所建立的套接字號聯繫起來,即將,名字賦予套接字,以指定本地半相關。其調用格式以下:
參數 socketfd 是由 socket() 調用返回的而且未做鏈接的套接字描述符(套接字號)。參數 myaddr 是賦給套接字 socketfd 的本地地址(名字),其長度可變,結構隨通訊域的不一樣而不一樣。 addrlen 代表了 name 的長度。
進程能夠把一個特定的 IP 地址捆綁到它的套接口上,但此 IP 地址必須是主機的一個接口。對於 TCP 客戶端,這就爲在此套接口上發送的 IP 數據包分配了源 IP 地址。對於服務器端,這樣作就限制了套接口只接收來自那些目的地址爲此 IP 地址的客戶連接。
對於 TCP ,調用函數 bind 能夠指定一個端口號,指定一個 IP 地址,能夠二者都指定,也能夠一個都不指定。對於服務器,通常指定衆所周知的端口號。而不指定具體的 IP 地址。若是 TCP 服務器不把地址綁到套接口上,那麼內核就把客戶所發 SYN 所在分組的目的IP 地址做爲服務器的源 IP 地址。
若指定端口號爲 0 ,則調用函數 bind 時,內核選擇一個臨時端口;但若指定一個通配IP 地址,則直到套接口以鏈接 (TCP) 或數據報已在套接口上發出 (UDP), 內核才選擇一個本地 IP 。
注意到在第四部分圖中,客戶端並無調用 bind 函數,由於對於客戶端來講,沒有必要指定具體的 IP 和端口,若是須要,內核會選擇一個源 IP 地址和一個臨時的端口。
TCP 客戶用 connect() 函數創建一個與 TCP 服務器的連接。Connect ()的調用格式以下:
參數 socket 是欲創建鏈接的本地套接字描述符。參數 servaddr 指出說明對方套接字地址結構指針。對方套接字地址長度由 addrlen 說明。
根據 TCP 的狀態轉移圖,函數 connect 致使從 CLOSED 狀態 ( 調用函數 socket建立套接口之後就一直處於此狀態 ) 轉到 SYN_SENT 狀態,若成功轉到 ESTABLISHED狀態。若是函數 connect 失敗,則原先建立的套接口就不可再用,必須關閉。如要從新嘗試,必須從新調用 socket ,再 connect 。
函數 listen 僅被 TCP 服務器調用,它作兩件事情:
<!--[if !supportLists]-->1. <!--[endif]-->當函數socket建立一個套接口時,它被假設爲一個主動套接口,也就是說,它是一個將調用connect發起連接的客戶套接口。函數listen將未連接的套接口轉換成被動套接口,告訴內核應接受指向此套接口的連接請求。根據TCP狀態轉移圖,函數listen致使套接口狀態從CLOSED轉到LISTEN。
<!--[if !supportLists]-->2. <!--[endif]-->函數的第二個參數規定了內核爲此套接口排隊的最大連接個數。
通常而言,此函數應該在 socket 和 bind 以後,調用函數 accept 以前調用。
參數 backlog 的解析:
對於給定的監聽套接口 (listen 以後 ) ,內核要維護兩個隊列:一個是處於三次握手過程當中(即客戶端調用 connect ,服務器端收到 SYN ,並返回 ACK 和 SYN 後,在等待客戶端的 ACK ),處於 SYN_RCVD 狀態;另外一個是從 connect 成功,處於 ESTABLISHED狀態。
兩個隊列之和不能超過 backlog 。
Accept 函數由 TCP 服務器調用,從已完成鏈接隊列頭返回一個已完成的連接。若已完成隊列爲空,則進程睡眠(假定套接口爲缺省的阻塞方式)。用於使服務器等待來自某客戶進程的實際鏈接。
參數 cliaddr 和 addrlen 用來返回連接對方進程(客戶端)的協議地址。
若函數成功返回,返回值是一個由內核自動生成的全新的描述字,表明與客戶端的連接。當咱們討論函數 accept 時,常把它的第一個參數稱爲監聽套接口描述字(由 socket 生成的描述字);把它的返回值稱爲已鏈接套接口描述字。
1. Windows Sockets 網絡程序設計大全
適合於WinSock編程入門。
2. Unix Networking Programming 3rd ed
很經典的書呀,若是你學習Unix Socket編程,你必須買的,學習WinSock也有做用的,由於WinSock是參考的Unix Socket。
3. Windows網絡編程技術
講了Win2000下的WinSock編程,講了TCP/IP, Netbios, IPX/SPX, ATM等在Windows下的編程,有不少代碼,還有一個MS Platform SDK的東西,這但是很可貴的。對了,還有QoS和Raw Socket編程的程序例子。
http://blog.163.com/jiams_wang/blog/static/30339149201242335530940/