程式在使用套接字前,首先必須擁有乙個套接字,系統呼叫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
有關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()之前呼叫。<
socket程式設計原理
if newsock accept mysock.daemonsock,addr,len 1 return 1 accept error.set this socket as a non blocking socket.ioctl newsock,fionbio,flag fd set newsoc...
socket程式設計(三)
伺服器端盡可能使用reuseaddr 在繫結之前盡可能呼叫setsockopt來設定reuseaddr套接字選項。使用reuseaddr選項可以使得不必等待time wait狀態消失可以重啟伺服器。echoserver.cpp include include include include incl...
socket程式設計原理(六)
closesocket sock exit 0 2.5 乙個通用的例項程式 在上一節中,我們介紹了乙個簡單的socket程式例項。從這個例子我們可以看出,使用socket程式設計幾乎有乙個模式,即所有的程式幾乎毫無例外地按相同的順序呼叫相同的函式。因此我們可以設想,設計乙個中間層,它向上提供幾個簡單...