socket編程原理(三)

程序在使用套接字前,首先必須擁有一個套接字,系統調用socket()嚮應用程序提供創建套接字的手段,其調用格式如下:
SOCKET PASCAL FAR socket(int af, int type, int protocol);
該調用要接收三個參數:af、type、protocol。參數af指定通信發生的區域,UNIX系統支持的地址族有:AF_UNIX、AF_INET、AF_NS等,而DOS、WINDOWS中僅支持AF_INET,它是網際網區域。因此,地址族與協議族相同。參數type 描述要建立的套接字的類型。參數protocol說明該套接字使用的特定協議,如果調用者不希望特別指定使用的協議,則置爲0,使用默認的連接模式。根據這三個參數建立一個套接字,並將相應的資源分配給它,同時返回一個整型套接字號。因此,socket()系統調用實際上指定了相關五元組中的"協議"這一元。
有關socket()的詳細描述參看5.2.23。
2.3.2 指定本地地址──bind()
當一個套接字用socket()創建後,存在一個名字空間(地址族),但它沒有被命名。bind()將套接字地址(包括本地主機地址和本地端口地址)與所創建的套接字號聯繫起來,即將名字賦予套接字,以指定本地半相關。其調用格式如下:
int PASCAL FAR bind(SOCKET s, const struct sockaddr FAR * name, int namelen);
參數s是由socket()調用返回的並且未作連接的套接字描述符(套接字號)。參數name 是賦給套接字s的本地地址(名字),其長度可變,結構隨通信域的不同而不同。namelen表明了name的長度。
如果沒有錯誤發生,bind()返回0。否則返回值SOCKET_ERROR。
地址在建立套接字通信過程中起着重要作用,作爲一個網絡應用程序設計者對套接字地址結構必須有明確認識。例如,UNIX BSD有一組描述套接字地址的數據結構,其中使用TCP/IP協議的地址結構爲:
struct sockaddr_in{
short sin_family; /*AF_INET*/
u_short sin_port; /*16位端口號,網絡字節順序*/
struct in_addr sin_addr; /*32位IP地址,網絡字節順序*/
char sin_zero[8]; /*保留*/
}
有關bind()的詳細描述參看5.2.2。
2.3.3 建立套接字連接──connect()與accept()
這兩個系統調用用於完成一個完整相關的建立,其中connect()用於建立連接。無連接的套接字進程也可以調用connect(),但這時在進程之間沒有實際的報文交換,調用將從本地操作系統直接返回。這樣做的優點是程序員不必爲每一數據指定目的地址,而且如果收到的一個數據報,其目的端口未與任何套接字建立"連接",便能判斷該端口不可操作。而accept()用於使服務器等待來自某客戶進程的實際連接。
connect()的調用格式如下:
int PASCAL FAR connect(SOCKET s, const struct sockaddr FAR * name, int namelen);
參數s是欲建立連接的本地套接字描述符。參數name指出說明對方套接字地址結構的指針。對方套接字地址長度由namelen說明。
如果沒有錯誤發生,connect()返回0。否則返回值SOCKET_ERROR。在面向連接的協議中,該調用導致本地系統和外部系統之間連接實際建立。
由於地址族總被包含在套接字地址結構的前兩個字節中,並通過socket()調用與某個協議族相關。因此bind()和connect()無須協議作爲參數。
有關connect()的詳細描述參看5.2.4。
accept()的調用格式如下:
SOCKET PASCAL FAR accept(SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen);
參數s爲本地套接字描述符,在用做accept()調用的參數前應該先調用過listen()。addr 指向客戶方套接字地址結構的指針,用來接收連接實體的地址。addr的確切格式由套接字創建時建立的地址族決定。addrlen 爲客戶方套接字地址的長度(字節數)。如果沒有錯誤發生,accept()返回一個SOCKET類型的值,表示接收到的套接字的描述符。否則返回值INVALID_SOCKET。
accept()用於面向連接服務器。參數addr和addrlen存放客戶方的地址信息。調用前,參數addr 指向一個初始值爲空的地址結構,而addrlen 的初始值爲0;調用accept()後,服務器等待從編號爲s的套接字上接受客戶連接請求,而連接請求是由客戶方的connect()調用發出的。當有連接請求到達時,accept()調用將請求連接隊列上的第一個客戶方套接字地址及長度放入addr 和addrlen,並創建一個與s有相同特性的新套接字號。新的套接字可用於處理服務器併發請求。
有關accept()的詳細描述參看5.2.1。
四個套接字系統調用,socket()、bind()、connect()、accept(),可以完成一個完全五元相關的建立。socket()指定五元組中的協議元,它的用法與是否爲客戶或服務器、是否面向連接無關。bind()指定五元組中的本地二元,即本地主機地址和端口號,其用法與是否面向連接有關:在服務器方,無論是否面向連接,均要調用bind();在客戶方,若採用面向連接,則可以不調用bind(),而通過connect()自動完成。若採用無連接,客戶方必須使用bind()以獲得一個唯一的地址。
以上討論僅對客戶/服務器模式而言,實際上套接字的使用是非常靈活的,唯一需遵循的原則是進程通信之前,必須建立完整的相關。
2.3.4 監聽連接──listen()
此調用用於面向連接服務器,表明它願意接收連接。listen()需在accept()之前調用,其調用格式如下:
int PASCAL FAR listen(SOCKET s, int backlog);
參數s標識一個本地已建立、尚未連接的套接字號,服務器願意從它上面接收請求。backlog表示請求連接隊列的最大長度,用於限制排隊請求的個數,目前允許的最大值爲5。如果沒有錯誤發生,listen()返回0。否則它返回SOCKET_ERROR。
listen()在執行調用過程中可爲沒有調用過bind()的套接字s完成所必須的連接,並建立長度爲backlog的請求連接隊列。 
調用listen()是服務器接收一個連接請求的四個步驟中的第三步。它在調用socket()分配一個流套接字,且調用bind()給s賦於一個名字之後調用,而且一定要在accept()之前調用。<

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