C++-WinSocket編程(轉(zhuǎn))_第1頁
C++-WinSocket編程(轉(zhuǎn))_第2頁
C++-WinSocket編程(轉(zhuǎn))_第3頁
C++-WinSocket編程(轉(zhuǎn))_第4頁
C++-WinSocket編程(轉(zhuǎn))_第5頁
免費預覽已結(jié)束,剩余1頁可下載查看

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

1、C+ WinSocket編程(轉(zhuǎn))2008-10-23 14:43推薦精選本文是我在進行MS-Windows、HP-Unix網(wǎng)絡編程的實踐過程中總結(jié)出來的一些經(jīng)驗,僅供大家參考。本文所談到的Socket函數(shù)如果沒有特別說明,都是指的Windows Socket API。一、WSAStartup函數(shù) int WSAStartup( WORD wVersionRequested, LPWSADATA lpWSAData ); 使用Socket的程序在使用Socket之前必須調(diào)用WSAStartup函數(shù)。該函數(shù)的第一個參數(shù)指明程序請求使用的Socket版本,其中高位字節(jié)指明副版本、低位字節(jié)指明主版本

2、;操作系統(tǒng)利用第二個參數(shù)返回請求的Socket的版本信息。當一個應用程序調(diào)用WSAStartup函數(shù)時,操作系統(tǒng)根據(jù)請求的Socket版本來搜索相應的Socket庫,然后綁定找到的Socket庫到該應用程序中。以后應用程序就可以調(diào)用所請求的Socket庫中的其它Socket函數(shù)了。該函數(shù)執(zhí)行成功后返回0。例:假如一個程序要使用2.1版本的Socket,那么程序代碼如下 wVersionRequested = MAKEWORD( 2, 1 ); err = WSAStartup( wVersionRequested, &wsaData );二、WSACleanup函數(shù) int WSACleanu

3、p (void); 應用程序在完成對請求的Socket庫的使用后,要調(diào)用WSACleanup函數(shù)來解除與Socket庫的綁定并且釋放Socket庫所占用的系統(tǒng)資源。三、socket函數(shù) SOCKET socket( int af, int type, int protocol ); 應用程序調(diào)用socket函數(shù)來創(chuàng)建一個能夠進行網(wǎng)絡通信的套接字。第一個參數(shù)指定應用程序使用的通信協(xié)議的協(xié)議族,對于TCP/IP協(xié)議族,該參數(shù)置PF_INET;第二個參數(shù)指定要創(chuàng)建的套接字類型,流套接字類型為SOCK_STREAM、數(shù)據(jù)報套接字類型為SOCK_DGRAM;第三個參數(shù)指定應用程序所使用的通信協(xié)議。該函數(shù)

4、如果調(diào)用成功就返回新創(chuàng)建的套接字的描述符,如果失敗就返回INVALID_SOCKET。套接字描述符是一個整數(shù)類型的值。每個進程的進程空間里都有一個套接字描述符表,該表中存放著套接字描述符和套接字數(shù)據(jù)結(jié)構的對應關系。該表中有一個字段存放新創(chuàng)建的套接字的描述符,另一個字段存放套接字數(shù)據(jù)結(jié)構的地址,因此根據(jù)套接字描述符就可以找到其對應的套接字數(shù)據(jù)結(jié)構。每個進程在自己的進程空間里都有一個套接字描述符表但是套接字數(shù)據(jù)結(jié)構都是在操作系統(tǒng)的內(nèi)核緩沖里。下面是一個創(chuàng)建流套接字的例子: struct protoent *ppe; ppe=getprotobyname(tcp); SOCKET ListenSoc

5、ket=socket(PF_INET,SOCK_STREAM,ppe-p_proto);四、closesocket函數(shù) int closesocket( SOCKET s ); closesocket函數(shù)用來關閉一個描述符為s套接字。由于每個進程中都有一個套接字描述符表,表中的每個套接字描述符都對應了一個位于操作系統(tǒng)緩沖區(qū)中的套接字數(shù)據(jù)結(jié)構,因此有可能有幾個套接字描述符指向同一個套接字數(shù)據(jù)結(jié)構。套接字數(shù)據(jù)結(jié)構中專門有一個字段存放該結(jié)構的被引用次數(shù),即有多少個套接字描述符指向該結(jié)構。當調(diào)用closesocket函數(shù)時,操作系統(tǒng)先檢查套接字數(shù)據(jù)結(jié)構中的該字段的值,如果為1,就表明只有一個套接字描述

6、符指向它,因此操作系統(tǒng)就先把s在套接字描述符表中對應的那條表項清除,并且釋放s對應的套接字數(shù)據(jù)結(jié)構;如果該字段大于1,那么操作系統(tǒng)僅僅清除s在套接字描述符表中的對應表項,并且把s對應的套接字數(shù)據(jù)結(jié)構的引用次數(shù)減1。closesocket函數(shù)如果執(zhí)行成功就返回0,否則返回SOCKET_ERROR。五、send函數(shù) int send( SOCKET s, const char FAR *buf, int len, int flags ); 不論是客戶還是服務器應用程序都用send函數(shù)來向TCP連接的另一端發(fā)送數(shù)據(jù)。客戶程序一般用send函數(shù)向服務器發(fā)送請求,而服務器則通常用send函數(shù)來向客戶程序

7、發(fā)送應答。該函數(shù)的第一個參數(shù)指定發(fā)送端套接字描述符;第二個參數(shù)指明一個存放應用程序要發(fā)送數(shù)據(jù)的緩沖區(qū);第三個參數(shù)指明實際要發(fā)送的數(shù)據(jù)的字節(jié)數(shù);第四個參數(shù)一般置0。這里只描述同步Socket的send函數(shù)的執(zhí)行流程。當調(diào)用該函數(shù)時,send先比較待發(fā)送數(shù)據(jù)的長度len和套接字s的發(fā)送緩沖區(qū)的長度,如果len大于s的發(fā)送緩沖區(qū)的長度,該函數(shù)返回SOCKET_ERROR;如果len小于或者等于s的發(fā)送緩沖區(qū)的長度,那么send先檢查協(xié)議是否正在發(fā)送s的發(fā)送緩沖中的數(shù)據(jù),如果是就等待協(xié)議把數(shù)據(jù)發(fā)送完,如果協(xié)議還沒有開始發(fā)送s的發(fā)送緩沖中的數(shù)據(jù)或者s的發(fā)送緩沖中沒有數(shù)據(jù),那么send就比較s的發(fā)送緩沖區(qū)

8、的剩余空間和len,如果len大于剩余空間大小send就一直等待協(xié)議把s的發(fā)送緩沖中的數(shù)據(jù)發(fā)送完,如果len小于剩余空間大小send就僅僅把buf中的數(shù)據(jù)copy到剩余空間里(注意并不是send把s的發(fā)送緩沖中的數(shù)據(jù)傳到連接的另一端的,而是協(xié)議傳的,send僅僅是把buf中的數(shù)據(jù)copy到s的發(fā)送緩沖區(qū)的剩余空間里)。如果send函數(shù)copy數(shù)據(jù)成功,就返回實際copy的字節(jié)數(shù),如果send在copy數(shù)據(jù)時出現(xiàn)錯誤,那么send就返回SOCKET_ERROR;如果send在等待協(xié)議傳送數(shù)據(jù)時網(wǎng)絡斷開的話,那么send函數(shù)也返回SOCKET_ERROR。要注意send函數(shù)把buf中的數(shù)據(jù)成功co

9、py到s的發(fā)送緩沖的剩余空間里后它就返回了,但是此時這些數(shù)據(jù)并不一定馬上被傳到連接的另一端。如果協(xié)議在后續(xù)的傳送過程中出現(xiàn)網(wǎng)絡錯誤的話,那么下一個Socket函數(shù)就會返回SOCKET_ERROR。(每一個除send外的Socket函數(shù)在執(zhí)行的最開始總要先等待套接字的發(fā)送緩沖中的數(shù)據(jù)被協(xié)議傳送完畢才能繼續(xù),如果在等待時出現(xiàn)網(wǎng)絡錯誤,那么該Socket函數(shù)就返回SOCKET_ERROR)注意:在Unix系統(tǒng)下,如果send在等待協(xié)議傳送數(shù)據(jù)時網(wǎng)絡斷開的話,調(diào)用send的進程會接收到一個SIGPIPE信號,進程對該信號的默認處理是進程終止。六、recv函數(shù) int recv( SOCKET s, c

10、har FAR *buf, int len, int flags ); 不論是客戶還是服務器應用程序都用recv函數(shù)從TCP連接的另一端接收數(shù)據(jù)。該函數(shù)的第一個參數(shù)指定接收端套接字描述符;第二個參數(shù)指明一個緩沖區(qū),該緩沖區(qū)用來存放recv函數(shù)接收到的數(shù)據(jù);第三個參數(shù)指明buf的長度;第四個參數(shù)一般置0。這里只描述同步Socket的recv函數(shù)的執(zhí)行流程。當應用程序調(diào)用recv函數(shù)時,recv先等待s的發(fā)送緩沖中的數(shù)據(jù)被協(xié)議傳送完畢,如果協(xié)議在傳送s的發(fā)送緩沖中的數(shù)據(jù)時出現(xiàn)網(wǎng)絡錯誤,那么recv函數(shù)返回SOCKET_ERROR,如果s的發(fā)送緩沖中沒有數(shù)據(jù)或者數(shù)據(jù)被協(xié)議成功發(fā)送完畢后,recv先檢

11、查套接字s的接收緩沖區(qū),如果s接收緩沖區(qū)中沒有數(shù)據(jù)或者協(xié)議正在接收數(shù)據(jù),那么recv就一直等待,只到協(xié)議把數(shù)據(jù)接收完畢。當協(xié)議把數(shù)據(jù)接收完畢,recv函數(shù)就把s的接收緩沖中的數(shù)據(jù)copy到buf中(注意協(xié)議接收到的數(shù)據(jù)可能大于buf的長度,所以在這種情況下要調(diào)用幾次recv函數(shù)才能把s的接收緩沖中的數(shù)據(jù)copy完。recv函數(shù)僅僅是copy數(shù)據(jù),真正的接收數(shù)據(jù)是協(xié)議來完成的),recv函數(shù)返回其實際copy的字節(jié)數(shù)。如果recv在copy時出錯,那么它返回SOCKET_ERROR;如果recv函數(shù)在等待協(xié)議接收數(shù)據(jù)時網(wǎng)絡中斷了,那么它返回0。注意:在Unix系統(tǒng)下,如果recv函數(shù)在等待協(xié)議接

12、收數(shù)據(jù)時網(wǎng)絡斷開了,那么調(diào)用recv的進程會接收到一個SIGPIPE信號,進程對該信號的默認處理是進程終止。七、bind函數(shù) int bind( SOCKET s, const struct sockaddr FAR *name, int namelen ); 當創(chuàng)建了一個Socket以后,套接字數(shù)據(jù)結(jié)構中有一個默認的IP地址和默認的端口號。一個服務程序必須調(diào)用bind函數(shù)來給其綁定一個IP地址和一個特定的端口號。客戶程序一般不必調(diào)用bind函數(shù)來為其Socket綁定IP地址和斷口號。該函數(shù)的第一個參數(shù)指定待綁定的Socket描述符;第二個參數(shù)指定一個sockaddr結(jié)構,該結(jié)構是這樣定義的:

13、 struct sockaddr u_short sa_family; char sa_data14; ; sa_family指定地址族,對于TCP/IP協(xié)議族的套接字,給其置AF_INET。當對TCP/IP協(xié)議族的套接字進行綁定時,我們通常使用另一個地址結(jié)構: struct sockaddr_in short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero8; ; 其中sin_family置AF_INET;sin_port指明端口號;sin_addr結(jié)構體中只有一個唯一的字段s_addr,表示IP地址,

14、該字段是一個整數(shù),一般用函數(shù)inet_addr()把字符串形式的IP地址轉(zhuǎn)換成unsigned long型的整數(shù)值后再置給s_addr。有的服務器是多宿主機,至少有兩個網(wǎng)卡,那么運行在這樣的服務器上的服務程序在為其Socket綁定IP地址時可以把htonl(INADDR_ANY)置給s_addr,這樣做的好處是不論哪個網(wǎng)段上的客戶程序都能與該服務程序通信;如果只給運行在多宿主機上的服務程序的Socket綁定一個固定的IP地址,那么就只有與該IP地址處于同一個網(wǎng)段上的客戶程序才能與該服務程序通信。我們用0來填充sin_zero數(shù)組,目的是讓sockaddr_in結(jié)構的大小與sockaddr結(jié)構的

15、大小一致。下面是一個bind函數(shù)調(diào)用的例子: struct sockaddr_in saddr; saddr.sin_family = AF_INET; saddr.sin_port = htons(8888); saddr.sin_addr.s_addr = htonl(INADDR_ANY); bind(ListenSocket,(struct sockaddr *)&saddr,sizeof(saddr);八、listen函數(shù) int listen( SOCKET s, int backlog ); 服務程序可以調(diào)用listen函數(shù)使其流套接字s處于監(jiān)聽狀態(tài)。處于監(jiān)聽狀態(tài)的流套接字s將維

16、護一個客戶連接請求隊列,該隊列最多容納backlog個客戶連接請求。假如該函數(shù)執(zhí)行成功,則返回0;如果執(zhí)行失敗,則返回SOCKET_ERROR。九、accept函數(shù) SOCKET accept( SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen ); 服務程序調(diào)用accept函數(shù)從處于監(jiān)聽狀態(tài)的流套接字s的客戶連接請求隊列中取出排在最前的一個客戶請求,并且創(chuàng)建一個新的套接字來與客戶套接字創(chuàng)建連接通道,如果連接成功,就返回新創(chuàng)建的套接字的描述符,以后與客戶套接字交換數(shù)據(jù)的是新創(chuàng)建的套接字;如果失敗就返回INVALID_SOCKET。該函數(shù)

17、的第一個參數(shù)指定處于監(jiān)聽狀態(tài)的流套接字;操作系統(tǒng)利用第二個參數(shù)來返回新創(chuàng)建的套接字的地址結(jié)構;操作系統(tǒng)利用第三個參數(shù)來返回新創(chuàng)建的套接字的地址結(jié)構的長度。下面是一個調(diào)用accept的例子: struct sockaddr_in ServerSocketAddr; int addrlen; addrlen=sizeof(ServerSocketAddr); ServerSocket=accept(ListenSocket,(struct sockaddr *)&ServerSocketAddr,&addrlen);十、connect函數(shù) int connect( SOCKET s, const struct sockaddr FAR *name, int namelen ); 客戶程序調(diào)用connect函數(shù)來使客戶Socket s與監(jiān)聽于name所指定的計算機的特定端口上的服務Socket進行連接。如果連接成功,connect返回0;如果失敗則返回SOC

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論