隨筆-22  評論-8  文章-0  trackbacks-0
          對于SOCKET在這里我不想究其歷史,我只想說其時它是一種進程通訊的方式,簡言之就是調(diào)用這個網(wǎng)絡(luò)庫的一些API函數(shù)就能實現(xiàn)分布在不同主機的相關(guān)進程之間的數(shù)據(jù)交換.

          SOCKET中首先我們要理解如下幾個定義概念:

          一是IP地址:IP Address我想很容易理解,就是依照TCP/IP協(xié)議分配給本地主機的網(wǎng)絡(luò)地址,就向兩個進程要通訊,任一進程要知道通訊對方的位置,位置如何來確定,就用對方的IP

          二是端口號:用來標識本地通訊進程,方便OS提交數(shù)據(jù).就是說進程指定了對方進程的網(wǎng)絡(luò)IP,但這個IP只是用來標識進程所在的主機,如何來找到運行在這個主機的這個進程呢,就用端口號.

          三是連接:指兩個進程間的通訊鏈路.

          四是半相關(guān):網(wǎng)絡(luò)中用一個三元組可以在全局唯一標志一個進程: 
          (協(xié)議,本地地址,本地端口號)這樣一個三元組,叫做一個半相關(guān),它指定連接的每半部分。 

          五是全相關(guān) 
          一個完整的網(wǎng)間進程通信需要由兩個進程組成,并且只能使用同一種高層協(xié)議。也就是說,不可能通信的一端用TCP協(xié)議,而另一端用UDP協(xié)議。因此一個完整的網(wǎng)間通信需要一個五元組來標識:(協(xié)議,本地地址,本地端口號,遠地地址,遠地端口號) 
          這樣一個五元組,叫做一個相關(guān)(association),即兩個協(xié)議相同的半相關(guān)才能組合成一個合適的相關(guān),或完全指定組成一連接。 

          客戶/服務(wù)器模式 
          在TCP/IP網(wǎng)絡(luò)應(yīng)用中,通信的兩個進程間相互作用的主要模式是客戶/服務(wù)器模式(Client/Server model),即客戶向服務(wù)器發(fā)出服務(wù)請求,服務(wù)器接收到請求后,提供相應(yīng)的服務(wù)。客戶/服務(wù)器模式的建立基于以下兩點:首先,建立網(wǎng)絡(luò)的起因是網(wǎng)絡(luò)中軟硬件資源、運算能力和信息不均等,需要共享,從而造就擁有眾多資源的主機提供服務(wù),資源較少的客戶請求服務(wù)這一非對等作用。其次,網(wǎng)間進程通信完全是異步的,相互通信的進程間既不存在父子關(guān)系,又不共享內(nèi)存緩沖區(qū),因此需要一種機制為希望通信的進程間建立聯(lián)系,為二者的數(shù)據(jù)交換提供同步,這就是基涌紀紀戶/服務(wù)器模式的TCP/IP。 

          客戶/服務(wù)器模式鑰紀紀作過程中采取的是主動請求方式: 

          首先服務(wù)器方要先啟動,并根據(jù)請求提供相應(yīng)服務(wù): 

          1. 打開一通信通道并告知本地主機,它愿意在某一公認地址上(周知口,如FTP為21)接收客戶請求; 

          2. 等待客戶請求到達該端口; 

          3. 接收到重復(fù)服務(wù)請求,處理該請求并發(fā)送應(yīng)答信號。接收到并發(fā)服務(wù)請求,要激活一新進程來處理這個客戶請求(如UNIX系統(tǒng)中用fork、exec)。新進程處理此客戶請求,并不需要對其它請求作出應(yīng)答。服務(wù)完成后,關(guān)閉此新進程與客戶的通信鏈路,并終止。 

          4. 返回第二步,等待另一客戶請求。 

          5. 關(guān)閉服務(wù)器 


          客戶方: 
          1. 打開一通信通道,并連接到服務(wù)器所在主機的特定端口; 

          2. 向服務(wù)器發(fā)服務(wù)請求報文,等待并接收應(yīng)答;繼續(xù)提出請求...... 

          3. 請求結(jié)束后關(guān)閉通信通道并終止。 

          從上面所描述過程可知: 
          1. 客戶與服務(wù)器進程的作用是非對稱的,因此編碼不同。 

          2. 服務(wù)進程一般是先涌紀紀戶請求而啟動的。只要系統(tǒng)運行,該服務(wù)進程一直存在,直到正常或強迫終止。 


          介紹完基礎(chǔ)知識,下面就介紹一些API函數(shù):

          創(chuàng)建套接字──socket() 
          應(yīng)用程序在使用套接字前,首先必須擁有一個套接字,系統(tǒng)調(diào)用socket()向應(yīng)用程序提供創(chuàng)建套接字的手段,其調(diào)用格式如下: 
          SOCKET PASCAL FAR socket(int af, int type, int protocol); 
          該調(diào)用要接收三個參數(shù):af、type、protocol。
          參數(shù)af指定通信發(fā)生的區(qū)域,:AF_UNIX、AF_INET、AF_NS等,而DOS、WINDOWS中僅支持AF_INET,它是網(wǎng)際網(wǎng)區(qū)域。因此,地址族與協(xié)議族相同。
          參數(shù)type 描述要建立的套接字的類型。這里分三種:
          一是TCP流式套接字(SOCK_STREAM)提供了一個面向連接、可靠的數(shù)據(jù)傳輸服務(wù),數(shù)據(jù)無差錯、無重復(fù)地發(fā)送,且按發(fā)送順序接收。內(nèi)設(shè)流量控制,避免數(shù)據(jù)流超限;數(shù)據(jù)被看作是字節(jié)流,無長度限制。文件傳送協(xié)議(FTP)即使用流式套接字。 

          二是數(shù)據(jù)報式套接字(SOCK_DGRAM)提供了一個無連接服務(wù)。數(shù)據(jù)包以獨立包形式被發(fā)送,不提供無錯保證,數(shù)據(jù)可能丟失或重復(fù),并且接收順序混亂。網(wǎng)絡(luò)文件系統(tǒng)(NFS)使用數(shù)據(jù)報式套接字。
          三是原始式套接字(SOCK_RAW)該接口允許對較低層協(xié)議,如IP、ICMP直接訪問。常用于檢驗新的協(xié)議實現(xiàn)或訪問現(xiàn)有服務(wù)中配置的新設(shè)備.參數(shù)protocol說明該套接字使用的特定協(xié)議,如果調(diào)用者不希望特別指定使用的協(xié)議,則置為0,使用默認的連接模式。根據(jù)這三個參數(shù)建立一個套接字,并將相應(yīng)的資源分配給它,同時返回一個整型套接字號。因此,socket()系統(tǒng)調(diào)用實際上指定了相關(guān)五元組中的“協(xié)議”這一元。  


          指定本地地址──bind() 

          當一個套接字用socket()創(chuàng)建后,存在一個名字空間(地址族),但它沒有被命名。bind()將套接字地址(包括本地主機地址和本地端口地址)與所創(chuàng)建的套接字號聯(lián)系起來,即將名字賦予套接字,以指定本地半相關(guān)。其調(diào)用格式如下: 
          int PASCAL FAR bind(SOCKET s, const struct sockaddr FAR * name, int namelen); 
          參數(shù)s是由socket()調(diào)用返回的并且未作連接的套接字描述符(套接字號)。
          參數(shù)name 是賦給套接字s的本地地址(名字),其長度可變,結(jié)構(gòu)隨通信域的不同而不同。
          namelen表明了name的長度.如果沒有錯誤發(fā)生,bind()返回0。否則返回SOCKET_ERROR。  


          建立套接字連接──connect()與accept() 

          這兩個系統(tǒng)調(diào)用用于完成一個完整相關(guān)的建立,其中connect()用于建立連接。無連接的套接字進程也可以調(diào)用connect(),但這時在進程之間沒有實際的報文交換,調(diào)用將從本地操作系統(tǒng)直接返回。這樣做的優(yōu)點是程序員不必為每一數(shù)據(jù)指定目的地址,而且如果收到的一個數(shù)據(jù)報,其目的端口未與任何套接字建立“連接”,便能判斷該端靠紀紀可操作。而accept()用于使服務(wù)器等待來自某客戶進程的實際連接。 
          connect()的調(diào)用格式如下: 
          int PASCAL FAR connect(SOCKET s, const struct sockaddr FAR * name, int namelen); 
          參數(shù)s是欲建立連接的本地套接字描述符。參數(shù)name指出說明對方套接字地址結(jié)構(gòu)的指針。對方套接字地址長度由namelen說明。 
          如果沒有錯誤發(fā)生,connect()返回0。否則返回值SOCKET_ERROR。在面向連接的協(xié)議中,該調(diào)用導(dǎo)致本地系統(tǒng)和外部系統(tǒng)之間連接實際建立。 
          由于地址族總被包含在套接字地址結(jié)構(gòu)的前兩個字節(jié)中,并通過socket()調(diào)用與某個協(xié)議族相關(guān)。因此bind()和connect()無須協(xié)議作為參數(shù)。  
          accept()的調(diào)用格式如下: 
          SOCKET PASCAL FAR accept(SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen); 
          參數(shù)s為本地套接字描述符,在用做accept()調(diào)用的參數(shù)前應(yīng)該先調(diào)用過listen()。
          addr 指向客戶方套接字地址結(jié)構(gòu)的指針,用來接收連接實體的地址。addr的確切格式由套接字創(chuàng)建時建立的地址族決定。
          addrlen 為客戶方套接字地址的長度(字節(jié)數(shù))。如果沒有錯誤發(fā)生,accept()返回一個SOCKET類型的值,表示接收到的套接字的描述符。否則返回值INVALID_SOCKET。 

          accept()用于面向連接服務(wù)器。參數(shù)addr和addrlen存放客戶方的地址信息。調(diào)用前,參數(shù)addr 指向一個初始值為空的地址結(jié)構(gòu),而addrlen 的初始值為0;調(diào)用accept()后,服務(wù)器等待從編號為s的套接字上接受客戶連接請求,而連接請求是由客戶方的connect()調(diào)用發(fā)出的。當有連接請求到達時,accept()調(diào)用將請求連接隊列上的第一個客戶方套接字地址及長度放入addr 和addrlen,并創(chuàng)建一個與s有相同特性的新套接字號。新的套接字可用于處理服務(wù)器并發(fā)請求。 

          四個套接字系統(tǒng)調(diào)用,socket()、bind()、connect()、accept(),可以完成一個完全五元相關(guān)的建立。socket()指定五元組中的協(xié)議元,它的用法與是否為客戶或服務(wù)器、是否面向連接無關(guān)。bind()指定五元組中的本地二元,即本地主機地址和端口號,其用法與是否面向連接有關(guān):在服務(wù)器方,無論是否面向連接,均要調(diào)用bind(),若采用面向連接,則可以不調(diào)用bind(),而通過connect()自動完成。若采用無連接,客戶方必須使用bind()以獲得一個唯一的地址。 

          監(jiān)聽連接──listen() 

          此調(diào)用用于面向連接服務(wù)器,表明它愿意接收連接。listen()需在accept()之前調(diào)用,其調(diào)用格式如下: 
          int PASCAL FAR listen(SOCKET s, int backlog); 
          參數(shù)s標識一個本地已建立、尚未連接的套接字號,服務(wù)器愿意從它上面接收請求。
          backlog表示請求連接隊列的最大長度,用于限制排隊請求的個數(shù),目前允許的最大值為5。如果沒有錯誤發(fā)生,listen()返回0。否則它返回SOCKET_ERROR。 

          listen()在執(zhí)行調(diào)用過程中可為沒有調(diào)用過bind()的套接字s完成所必須的連接,并建立長度為backlog的請求連接隊列。 
          調(diào)用listen()是服務(wù)器接收一個連接請求的四個步驟中的第三步。它在調(diào)用socket()分配一個流套接字,且調(diào)用bind()給s賦于一個名字之后調(diào)用,而且一定要在accept()之前調(diào)用。 

          數(shù)據(jù)傳輸──send()與recv() 

          當一個連接建立以后,就可以傳輸數(shù)據(jù)了。常用的系統(tǒng)調(diào)用有send()和recv()。 
          send()調(diào)用用于鑰紀紀數(shù)s指定的已連接的數(shù)據(jù)報或流套接字上發(fā)送輸出數(shù)據(jù),格式如下: 
          int PASCAL FAR send(SOCKET s, const char FAR *buf, int len, int flags); 
          參數(shù)s為已連接的本地套接字描述符。buf 指向存有發(fā)送數(shù)據(jù)的緩沖區(qū)的指針,其長度由len 指定。
          flags 指定傳輸控制方式,如是否發(fā)送帶外數(shù)據(jù)等。如果沒有錯誤發(fā)生,send()返回總共發(fā)送的字節(jié)數(shù)。否則它返回SOCKET_ERROR。 

          recv()調(diào)用用于s指定的已連接的數(shù)據(jù)報或流套接字上接收輸入數(shù)據(jù),格式如下: 
          int PASCAL FAR recv(SOCKET s, char FAR *buf, int len, int flags); 
          參數(shù)s 為已連接的套接字描述符。buf指向接收輸入數(shù)據(jù)緩沖區(qū)的指針,其長度由len 指定。
          flags 指定傳輸控制方式,如是否接收帶外數(shù)據(jù)等。如果沒有錯誤發(fā)生,recv()返回總共接收的字節(jié)數(shù)。如果連接被關(guān)閉,返回0。否則它返回SOCKET_ERROR。  


          輸入/輸出多路復(fù)用──select() 

          select()調(diào)用用來檢測一個或多個套接字的狀態(tài)。對每一個套接字來說,這個調(diào)用可以請求讀、寫或錯誤狀態(tài)方面的信息。請求給定狀態(tài)的套接字集合由一個fd_set結(jié)構(gòu)指示。在返回時,此結(jié)構(gòu)被更新,以反映那些滿足特定條件的套接字的子集,同時, select()調(diào)用返回滿足條件的套接字的數(shù)目,其調(diào)用格式如下: 
          int PASCAL FAR select(int nfds, fd_set FAR * readfds, fd_set FAR * writefds, fd_set FAR * exceptfds, const struct timeval FAR * timeout); 
          參數(shù)nfds指明被檢查的套接字描述符的值域,此變量一般被忽略。 
          參數(shù)readfds指向要做讀檢測的套接字描述符集合的指針,調(diào)用者希望從中讀取數(shù)據(jù)。
          參數(shù)writefds 指向要做寫檢測的套接字描述符集合的指針。
          exceptfds指向要檢測是否出錯的套接字描述符集合的指針。
          timeout指向select()函數(shù)等待的最大時間,如果設(shè)為NULL則為阻塞操作。select()返回包含在fd_set結(jié)構(gòu)中已準備好的套接字描述符的總數(shù)目,或者是發(fā)生錯誤則返回SOCKET_ERROR。  


          關(guān)閉套接字──closesocket() 

          closesocket()關(guān)閉套接字s,并釋放分配給該套接字的資源;如果s涉及一個打開的TCP連接,則該連接被釋放。closesocket()的調(diào)用格式如下: 
          BOOL PASCAL FAR closesocket(SOCKET s); 
          參數(shù)s待關(guān)閉的套接字描述符。如果沒有錯誤發(fā)生,closesocket()返回0。否則返回值SOCKET_ERROR。  

          以上就是SOCKET API一些常用的API函數(shù),下面我在介紹C/S模式就是客戶機/服務(wù)器通訊模式,服務(wù)器啟動服務(wù)并在相應(yīng)端口內(nèi)偵聽,客戶機打開連接,完成通訊鏈路的建立后,雙方進行數(shù)據(jù)交互,完畢后關(guān)閉套接字.

           好了,SOCKET基礎(chǔ)我們就介紹到這里

          posted on 2011-06-27 10:46 Hukin 閱讀(202) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 康保县| 文山县| 广水市| 巴里| 丰台区| 雅安市| 丰城市| 安远县| 芒康县| 广昌县| 嵩明县| 赞皇县| 海伦市| 通渭县| 沂水县| 黄龙县| 墨玉县| 临汾市| 即墨市| 徐汇区| 格尔木市| 义乌市| 郧西县| 菏泽市| 静安区| 滦南县| 宁乡县| 霍邱县| 肥乡县| 咸宁市| 忻州市| 银川市| 常宁市| 徐水县| 阳朔县| 靖江市| 金阳县| 抚松县| 民权县| 兴义市| 准格尔旗|