VisualC網(wǎng)絡編程案例實戰(zhàn)之Socket套接字編程_第1頁
VisualC網(wǎng)絡編程案例實戰(zhàn)之Socket套接字編程_第2頁
VisualC網(wǎng)絡編程案例實戰(zhàn)之Socket套接字編程_第3頁
VisualC網(wǎng)絡編程案例實戰(zhàn)之Socket套接字編程_第4頁
VisualC網(wǎng)絡編程案例實戰(zhàn)之Socket套接字編程_第5頁
已閱讀5頁,還剩100頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、第2章 Socket套接字編程套接字是由美國伯克利大學提出并設(shè)計的一種在網(wǎng)絡中不同主機之間進展數(shù)據(jù)交換的通信橋梁。在實際生活中,人們所使用的網(wǎng)絡通信軟件功能均是基于Socket套接字作為通信橋梁實現(xiàn)。所以,套接字在網(wǎng)絡編程中,有著非常重要的作用。本章將向用戶介紹使用Socket套接字編程的相關(guān)概念以及實現(xiàn)方法。2.1 尋址方式和字節(jié)順序在講解套接字編程前,用戶需要首先理解一下什么是尋址方式和字節(jié)順序。在Socket套接字編程中,為了準確定位通信雙方和數(shù)據(jù)傳輸?shù)挠行?、完好性,編程時必須使用統(tǒng)一的尋址方式和字節(jié)排列順序。2.1.1 尋址方式因為套接字需要在各種網(wǎng)絡協(xié)議中使用,所以為了區(qū)分程序所使

2、用的網(wǎng)絡協(xié)議必須使用統(tǒng)一的尋址方式。例如,在TCP/IP協(xié)議通信中,用戶使用IP地址和端口號進展確定通信雙方。而在其他的協(xié)議中不一定也使用該方式確定通信雙方。在WinsockSocket API中,用戶可以使用TCP/IP地址家族中統(tǒng)一的套接字地址構(gòu)造解決TCP/IP尋址中可能出現(xiàn)的問題。該套接字地址構(gòu)造定義如下:struct sockaddr_in short sin_family;/指定地址家族即地址格式 unsigned short sin_port;/端口號碼 struct in_addr sin_addr;/IP地址 char sin_zero8; /需要指定為0;在這個構(gòu)造中,成員

3、sin_family指定使用該套接字地址的地址家族。在這里必須設(shè)置為AF_INET,表示程序所使用的地址家族是TCP/IP。注意:該構(gòu)造的最后一個成員并未實際使用,主要是為了與第一個版本的套接字地址構(gòu)造大小一樣而設(shè)置。在實際使用時,將這8個字節(jié)直接設(shè)為0即可。該構(gòu)造成員變量sin_addr表示32位的IP地址構(gòu)造。其構(gòu)造定義如下: struct in_addr union struct unsigned char s_b1, s_b2,s_b3,s_b4; S_un_b;/用4個u_char字符描繪IP地址 struct unsigned short s_w1,s_w2; S_un_w;/用2

4、個u_short類型描繪IP地址 unsigned long S_addr;/用1個u_long類型描繪IP地址 S_un;通常,用戶在網(wǎng)絡編程中使用1個u_long類型的字符進展描繪IP地址即可。例如,使用IP地址構(gòu)造in_addr 進展描繪IP地址“。代碼如下:sockaddr_in addr;addr.sin_addr.S_un.S_addr=inet_addr(218.6.132.5);在程序中,首先定義sockaddr_in構(gòu)造對象addr,然后為IP地址構(gòu)造in_addr中的成員S_addr賦值。因為構(gòu)造成員S_addr所描繪的IP地址均為網(wǎng)絡字節(jié)順序,所以程序調(diào)用inet_add

5、r()函數(shù)將字符串IP轉(zhuǎn)換為以網(wǎng)絡字節(jié)順序排列的IP地址。2.1.2 字節(jié)順序在Socket套接字編程中,傳輸數(shù)據(jù)的排列順序以網(wǎng)絡字節(jié)順序和主機字節(jié)順序為主。通常情況下,假如用戶將數(shù)據(jù)通過網(wǎng)絡發(fā)送時,需要將數(shù)據(jù)轉(zhuǎn)換成以網(wǎng)絡字節(jié)順序排列,否那么可能造成數(shù)據(jù)損壞。假如用戶是將網(wǎng)絡中接收到的數(shù)據(jù)存儲在本地計算機上,那么需要將數(shù)據(jù)轉(zhuǎn)換成以主機字節(jié)順序排列。從數(shù)據(jù)存儲的角度來講,網(wǎng)絡字節(jié)順序即將數(shù)據(jù)中最重要的字節(jié)首先進展存儲,而主機字節(jié)順序那么將不重要的字節(jié)首先存儲。注意:IP地址構(gòu)造in_addr中的成員S_addr的值均是以網(wǎng)絡字節(jié)順序排列。1字節(jié)順序轉(zhuǎn)換函數(shù)在Winsock中提供了幾個關(guān)于網(wǎng)絡字節(jié)

6、順序與主機字節(jié)順序之間的轉(zhuǎn)換函數(shù)。函數(shù)定義如下:/將一個u_short類型的IP地址從主機字節(jié)順序轉(zhuǎn)換到網(wǎng)絡字節(jié)順序u_short htons (u_short hostshort );/將一個u_long類型的IP地址從主機字節(jié)順序轉(zhuǎn)換到網(wǎng)絡字節(jié)順序u_long htonl (u_long hostlong );/將一個u_long類型的IP地址從網(wǎng)絡字節(jié)順序轉(zhuǎn)換到主機字節(jié)順序u_long ntohl (u_long netlong );/將一個u_short類型的IP地址從網(wǎng)絡字節(jié)順序轉(zhuǎn)換到主機字節(jié)順序u_short ntohs (u_short netshort );/將一個字符串IP轉(zhuǎn)

7、換到以網(wǎng)絡字節(jié)順序排列的IP地址unsigned long inet_addr (const char FAR * cp);/將一個以網(wǎng)絡字節(jié)順序排列的IP地址轉(zhuǎn)換為一個字符串IPchar FAR * inet_ntoa (struct in_addr in);以上函數(shù)的使用均與操作系統(tǒng)平臺無關(guān)。因此,用戶使用這些函數(shù)編寫的程序能在所有操作系統(tǒng)平臺中運行。2實例程序在本節(jié)中,將編寫實例程序向用戶講解字節(jié)順序轉(zhuǎn)換函數(shù)的用法。代碼如下:./省略部分代碼sockaddr_in addr;/定義套接字地址構(gòu)造變量addr.sin_family=AF_INET;/指定地址家族為TCP/IPaddr.si

8、n_port=htons(80); /指定端口號/將字符串IP轉(zhuǎn)換為網(wǎng)絡字節(jié)順序排列的IPaddr.sin_addr.S_un.S_addr=inet_addr(127.0.0.1);/將網(wǎng)絡字節(jié)順序排列的IP轉(zhuǎn)換為字符串IPchar addres=inet_ntoa(addr.sin_addr.S_un.S_addr);在程序中,用戶首先使用函數(shù)inet_addr()將字符串IP“轉(zhuǎn)換為以網(wǎng)絡字節(jié)順序排列的IP并保存在IP地址構(gòu)造成員S_addr中。然后,再使用函數(shù)inet_ntoa()那么將該成員所表示的IP值轉(zhuǎn)換成字符串IP。2.1.3 Socket相關(guān)函數(shù)由于Windows網(wǎng)絡程序開發(fā)

9、均是基于Windows套接字實現(xiàn),所以本節(jié)將重點介紹MFC中的CSocket類以及使用CSocket類編程的根本流程。1創(chuàng)立套接字使用CSocket類創(chuàng)立套接字對象是通過該類的構(gòu)造函數(shù)創(chuàng)立的。其原型如下:CSocket:CSocket( );例如,用戶創(chuàng)立CSocket類對象,代碼如下:CSocket sock;假如用戶需要創(chuàng)立套接字對象指針,那么應該使用關(guān)鍵字new進展創(chuàng)立。代碼如下:CSocket *sock;/定義套接字指針對象sock=new CSocket;/使用new關(guān)鍵字創(chuàng)立套接字2綁定地址信息假如用戶創(chuàng)立效勞器套接字,那么用戶應該調(diào)用該類的函數(shù)Bind()將套接字對象與效勞器地

10、址信息綁定在一起。其原型如下:BOOL Bind ( const SOCKADDR* lpSockAddr, int nSockAddrLen );該函數(shù)的作用是將套接字對象與效勞器地址構(gòu)造綁定在一起。假如函數(shù)調(diào)用成功,那么返回true。否那么,返回false。參數(shù)lpSockAddr指定將要綁定的效勞器地址構(gòu)造,參數(shù)nSockAddrLen表示地址構(gòu)造的長度。例如,用戶將上面創(chuàng)立的套接字對象與地址構(gòu)造綁定。代碼如下:CSocket sock;/創(chuàng)立套接字對象sockaddr_in addr;/定義套接字地址構(gòu)造變量addr.sin_family=AF_INET;/指定地址家族為TCP/IPa

11、ddr.sin_port=htons(80);/指定端口號/將字符串IP轉(zhuǎn)換為網(wǎng)絡字節(jié)順序排列的IPaddr.sin_addr.S_un.S_addr=inet_addr(127.0.0.1);sock.Bind(SOCKADDR*)addr,sizeof(addr);/綁定套接字與地址構(gòu)造./省略部分代碼在效勞器端,當?shù)刂沸畔⒔壎ㄌ捉幼殖晒?,還需要調(diào)用函數(shù)Listen()在指定端口監(jiān)聽客戶端的連接懇求。函數(shù)Listen()的原型如下:BOOL Listen( int nConnectionBacklog = 5 );參數(shù)nConnectionBacklog表示套接字監(jiān)聽客戶端懇求的最大數(shù)目

12、。該參數(shù)的有效范圍是15。默認為5,表示該套接字只能監(jiān)聽5個客戶端所發(fā)送的連接懇求。例如,套接字監(jiān)聽5個客戶端的連接懇求,代碼如下:CSocket sock;/創(chuàng)立套接字對象sockaddr_in addr;/定義套接字地址構(gòu)造變量addr.sin_family=AF_INET;/指定地址家族為TCP/IPaddr.sin_port=htons(80);/指定端口號/將字符串IP轉(zhuǎn)換為網(wǎng)絡字節(jié)順序排列的IPaddr.sin_addr.S_un.S_addr=inet_addr(127.0.0.1);sock.Bind(SOCKADDR*)addr,sizeof(addr);/綁定套接字與地址構(gòu)

13、造sock.Listen(5);/監(jiān)聽端口3連接效勞器客戶端創(chuàng)立套接字成功以后,可以調(diào)用函數(shù)Connect()向效勞器發(fā)送連接懇求。函數(shù)原型如下:BOOL Connect( const SOCKADDR* lpSockAddr, int nSockAddrLen );該函數(shù)調(diào)用成功,那么返回true。否那么,將返回false。參數(shù)lpSockAddr表示將連接的效勞器地址構(gòu)造。參數(shù)nSockAddrLen表示地址構(gòu)造的長度大小。例如,效勞器IP地址為“,端口為80,客戶端連接效勞器,代碼如下:CSocket sock;/創(chuàng)立套接字對象sockaddr_in addr;/定義套接字地址構(gòu)造變量a

14、ddr.sin_family=AF_INET;/指定地址家族為TCP/IPaddr.sin_port=htons(80);/指定端口號/將字符串IP轉(zhuǎn)換為網(wǎng)絡字節(jié)順序排列的IPaddr.sin_addr.S_un.S_addr=inet_addr(127.0.0.1);sock.Connect(SOCKADDR*)addr,sizeof(addr);/連接效勞器4數(shù)據(jù)交換無論是效勞器,還是客戶端都是通過函數(shù)Send()和Receive()進展數(shù)據(jù)交換。函數(shù)原型如下:virtual int Send( const void* lpBuf, int nBufLen, int nFlags = 0

15、);virtual int Receive( void* lpBuf, int nBufLen, int nFlags = 0 );其中,函數(shù)Send()用于發(fā)送指定緩沖區(qū)的數(shù)據(jù),函數(shù)Receive()用于接收對方發(fā)送的數(shù)據(jù),并將數(shù)據(jù)存放在指定緩沖區(qū)中。參數(shù)lpBuf表示數(shù)據(jù)緩沖區(qū)地址。參數(shù)nBufLen表示數(shù)據(jù)緩沖區(qū)的大小。參數(shù)nFlags表示數(shù)據(jù)發(fā)送或接收的標志,一般情況下,該參數(shù)均設(shè)置為0。例如,使用這兩個函數(shù)進展數(shù)據(jù)的發(fā)送和接收。代碼如下:./省略部分代碼char buff=a;/定義并初始化數(shù)據(jù)緩沖區(qū)sock.Send(&buff,sizeof(buff),0);/發(fā)送數(shù)據(jù)緩

16、沖區(qū)中的數(shù)據(jù)sock.Receive(&buff, sizeof(buff),0);/接收數(shù)據(jù)并將數(shù)據(jù)存放在數(shù)據(jù)緩沖區(qū)中5關(guān)閉套接字對象當效勞器和客戶端的通信完成以后,用戶還必須調(diào)用函數(shù)Close()將套接字對象關(guān)閉。否那么,程序可能在退出時發(fā)生錯誤。該函數(shù)原型如下:virtual void Close( );例如,客戶端關(guān)閉套接字對象,代碼如下:./省略部分代碼sock.Close();/關(guān)閉套接字對象套接字關(guān)閉的同時,也將效勞器與客戶端之間連接關(guān)閉了。本節(jié)主要向用戶介紹了CSocket類的常用函數(shù)以及用法。當用戶創(chuàng)立VC應用程序時,假如沒有為應用程序指定支持Windows Sock

17、et,那么用戶必須手動添加該類的頭文件。否那么,程序?qū)⒉荒苁褂肅Socket類。2.2 Winsock網(wǎng)絡程序開發(fā)流程本節(jié)將向用戶講述基于Windows Socket的應用程序開發(fā)步驟,并將編寫實例程序向用戶介紹網(wǎng)絡應用程序的開發(fā)過程以及CSocket類的詳細使用方法。本節(jié)中的實例程序均在VC中進展編寫、調(diào)試。2.2.1 VC中創(chuàng)立工程的步驟用戶在VC中使用應用程序向?qū)?chuàng)立基于套接字的應用程序工程時,必須為該應用程序指定支持Windows Socket功能。否那么,創(chuàng)立的應用程序不能進展網(wǎng)絡通信。假如用戶創(chuàng)立工程工程成功,那么在應用程序向?qū)гO(shè)置的第二步,將詢問用戶是否需要在工程中支持Windo

18、ws Socket功能,如下圖。圖2.1 支持Windows Socket功能假如用戶在應用程序的第二步?jīng)]有選擇工程支持Windows Socket功能,那么在程序中手動添加代碼也可以到達同樣的目的。其代碼如下:#include /包含CSocket類的頭文件注意:頭文件中包含了CSocket類的變量以及函數(shù)定義。2.2.2 Winsock編程流程在本書的第1章中,已經(jīng)向用戶介紹了Winsock函數(shù)是用于網(wǎng)絡編程的Windows API函數(shù)。本章在前一節(jié)中,向用戶介紹了CSocket類的根本編程流程。所以,在本節(jié)中將向用戶介紹使用Socket API函數(shù)進展網(wǎng)絡程序開發(fā)的根本流程與方法。1初始

19、化和釋放套接字庫由于所有的Winsock函數(shù)均是從動態(tài)鏈接庫中導出的,但是,VC在默認情況下并沒有與該庫進展連接。所以,用戶需要在VC中進展相關(guān)設(shè)置,使其連接動態(tài)庫。添加方法是選擇“Project|“Settings命令,將彈出Project Settings對話框,如下圖。圖2.2 添加動態(tài)鏈接庫用戶在工程設(shè)置對話中,可以修改或添加庫模塊如下圖。在庫模塊中添加動態(tài)鏈接庫。這樣,程序就可以調(diào)用Winsock函數(shù)了。用戶必須首先從動態(tài)鏈接庫中調(diào)用函數(shù)WSAStartup()對該庫進展初始化,之后才能從該庫中繼續(xù)正確調(diào)用其他Winsock函數(shù)。否那么,將出現(xiàn)錯誤。函數(shù)WSAStartup()的原型

20、如下:int WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData);該函數(shù)調(diào)用成功,將返回0。否那么,調(diào)用函數(shù)失敗。參數(shù)wVersionRequested表示當前套接字庫的版本號。例如,當前套接字版本號為,那么將該參數(shù)設(shè)置為。代碼如下:WORD wVersionRequested=MAKEWORD(2,0);參數(shù)lpWSAData指向構(gòu)造體WSADATA的指針變量,表示獲取到的套接字庫詳細信息。該構(gòu)造體定義如下:typedef struct WSAData WORD wVersion;/庫文件建議應用程序使用的版本號 WORD wHigh

21、Version; /庫文件支持的最高版本 char szDescriptionWSADESCRIPTION_LEN+1;/描繪庫文件的字符串 char szSystemStatusWSASYS_STATUS_LEN+1;/系統(tǒng)狀態(tài)字符串 unsigned short iMaxSockets;/同時支持的最大套接字數(shù) unsigned short iMaxUdpDg;/已廢棄 char FAR * lpVendorInfo;/已廢棄 WSADATA, FAR * LPWSADATA; 用戶初始化套接字庫,代碼如下:WSAData data;/定義WSAData變量WORD wVersionReq

22、uested=MAKEWORD(2,0);/定義套接字庫版本號:WSAStartup (wVersionRequested,&data);/初始化套接字庫當程序退出時,用戶還應該調(diào)用函數(shù)WSACleanup()釋放該套接字庫。代碼如下::WSACleanup();2創(chuàng)立套接字句柄在Socket API中,創(chuàng)立套接字句柄的函數(shù)是socket()。該函數(shù)原型如下:SOCKET socket ( int af,/指定套接字所使用的地址格式,在本章中只能設(shè)置為AF_INET int type, /套接字類型 int protocol /假如參數(shù)type已經(jīng)指定套接字類型為TCP或UDP,那么該

23、參數(shù)可以設(shè)置為0);該函數(shù)執(zhí)行成功,將返回新創(chuàng)立的套接字句柄。否那么,將返回INVALID_SOCKET表示失敗。參數(shù)type的取值如表所示。表2.1 套接字類型取值例如,創(chuàng)立流式套接字的句柄。代碼如下:SOCKET s;/定義套接字句柄s=:socket(AF_INET, SOCK_STREAM,0);/創(chuàng)立并返回套接字句柄 套套接字類型取值接字類型取值 含含 義義SOCK_STREAM創(chuàng)建流式套接字(基于創(chuàng)建流式套接字(基于TCP協(xié)議)協(xié)議)SOCK_DGRAM創(chuàng)建數(shù)據(jù)報套接字(基于創(chuàng)建數(shù)據(jù)報套接字(基于UDP協(xié)議)協(xié)議)SOCK_RAW創(chuàng)建原始套接字(本書中未使用)創(chuàng)建原始套接字(本書中

24、未使用)3綁定地址信息對于效勞器而言,套接字創(chuàng)立成功后,還應該將套接字與地址構(gòu)造信息相關(guān)聯(lián)。實現(xiàn)這一功能的函數(shù)是bind()。該函數(shù)原型如下:int bind ( SOCKET s, /套接字句柄 const struct sockaddr FAR* name,/地址構(gòu)造信息 int namelen /地址構(gòu)造的大小 );該函數(shù)調(diào)用成功,那么返回0。否那么,函數(shù)調(diào)用失敗。例如,將套接字句柄綁定到本地地址,代碼如下:./省略部分代碼sockaddr_in addr;/定義套接字地址構(gòu)造變量addr.sin_family=AF_INET;/指定地址家族為TCP/IPaddr.sin_port=ht

25、ons(80);/指定端口號addr.sin_addr.S_un.S_addr=INADDR_ANY /表示效勞器可以接收任何計算機發(fā)來的懇求:bind(s,(sockaddr)&addr,sizeof(addr);/綁定套接字到指定地址構(gòu)造當效勞器程序?qū)⑻捉幼志浔壎ㄌ捉幼值刂烦晒r,那么調(diào)用函數(shù)listen()實現(xiàn)監(jiān)聽端口的功能。該函數(shù)原型如下:int listen ( SOCKET s, /實現(xiàn)監(jiān)聽功能的套接字句柄 int backlog /指定監(jiān)聽的最大連接數(shù)量 );該函數(shù)僅被用于流式套接字上。假如多個客戶端同時向效勞器發(fā)出連接懇求,并且已超過了最大監(jiān)聽數(shù),那么客戶端將返回錯誤

26、代碼。例如,程序在已創(chuàng)立的套接字s上進展監(jiān)聽,代碼如下:./省略部分代碼:listen(s,5);/在套接字上進展監(jiān)聽,并且將最大監(jiān)聽數(shù)指定為54連接客戶端程序連接效勞器使用函數(shù)connect()實現(xiàn)。函數(shù)原型如下:int connect ( SOCKET s, /套接字句柄 const struct sockaddr FAR* name,/將要連接的效勞器地址信息構(gòu)造指針 int namelen /地址信息構(gòu)造體長度 );例如,客戶端使用該函數(shù)連接地址為“,端口為80的效勞器。代碼如下:sockaddr_in addr;/定義套接字地址構(gòu)造變量addr.sin_family=AF_INET;

27、/指定地址家族為TCP/IPaddr.sin_port=htons(80);/指定端口號addr.sin_addr.S_un.S_addr=inet_addr(127.0.0.1);/指定效勞器地址SOCKET s;/定義套接字句柄s=:socket(AF_INET,SOCK_STREAM,0);/創(chuàng)立并返回套接字句柄:connect(s,( sockaddr)&addr,sizeof(addr);/連接效勞器.假如效勞器接收到客戶端的連接懇求,那么可以調(diào)用函數(shù)accept()承受該懇求。函數(shù)原型如下:SOCKET accept ( SOCKET s, /套接字句柄 struct so

28、ckaddr FAR* addr, /獲取連接對方的地址信息 int FAR* addrlen /地址長度 );該函數(shù)假如調(diào)用成功,那么返回一個新的套接字句柄,用于通信雙方數(shù)據(jù)的傳輸。5數(shù)據(jù)收發(fā)當用戶使用Winsock編程時,都是調(diào)用函數(shù)send()和recv()進展數(shù)據(jù)的發(fā)送和接收。函數(shù)原型如下:/發(fā)送數(shù)據(jù)函數(shù)int send (SOCKET s, const char FAR * buf, int len, int flags);/接收數(shù)據(jù)函數(shù)int recv (SOCKET s, char FAR* buf, int len, int flags); 兩個函數(shù)的各個參數(shù)表示的意義均一樣。

29、參數(shù)buf是指向數(shù)據(jù)緩沖區(qū)的指針變量,參數(shù)flags通常設(shè)置為0。注意:假如效勞器使用上面的函數(shù)進展數(shù)據(jù)收發(fā),那么參數(shù)s應該為監(jiān)聽函數(shù)返回的新套接字句柄。假如客戶端使用以上函數(shù)進展數(shù)據(jù)收發(fā),那么參數(shù)s應該為客戶端創(chuàng)立的套接字句柄。6關(guān)閉套接字當套接字使用完畢或程序退出時,用戶應該調(diào)用函數(shù)closesocket()關(guān)閉套接字句柄。函數(shù)原型如下:int closesocket ( SOCKET s /將關(guān)閉的套接字句柄);參數(shù)s表示即將關(guān)閉的套接字句柄。例如,用戶關(guān)閉前面創(chuàng)立的套接字句柄s,代碼如下::closesocket(s);本節(jié)主要向用戶講述了使用Winsock函數(shù)進展程序設(shè)計的根本流程,

30、并講解了部分常用函數(shù)的用法等知識。希望用戶在實際編程的過程中,能不斷地對本節(jié)知識進展回憶,加深理解。2.2.3 基于TCP的Sockets編程在本節(jié)中,將編寫一個簡單的TCP效勞器和TCP客戶端程序。這兩個實例程序均為控制臺程序窗口。1TCP效勞器首先,在VC中新建一個基于控制臺的應用程序工程,并將該工程命名為“TCP效勞器,如下圖。圖2.3 新建控制臺應用程序然后,單擊“OK按鈕進展應用程序類型的設(shè)置。在本節(jié)中,將新建的控制臺程序類型指定為一個空工程,如下圖。圖2.4 設(shè)置空的控制臺程序用戶還需要在VC中添加一個空白的C+源文件,名稱為TCPSEVER,如下圖。圖2.5 新建C+資源文件用戶

31、在新建的C+源文件中進展代碼編寫。代碼如下:編譯并運行程序,如下圖。圖2.6 效勞器啟動界面效勞器程序啟動以后,假如沒有客戶端向其發(fā)送連接懇求,那么效勞器將一直等待直到有客戶端程序連接。2TCP客戶端在VC中創(chuàng)立基于控制臺的應用程序,命名為“TCP客戶端。其方法與TCP效勞器的創(chuàng)立過程一樣。所以,在這里不再贅述,請讀者復習前面的相關(guān)內(nèi)容。在新建的C+源文件TCPClient中,用戶可以編寫客戶端的功能代碼。代碼如下:編譯并運行程序,如下圖。圖2.7 客戶端啟動界面假如用戶首先翻開效勞器程序,再翻開客戶端程序,那么效勞器會承受客戶端的連接懇求,而客戶端會顯示效勞器發(fā)送的歡送信息,如下圖。圖2.8

32、 翻開效勞器與客戶端本節(jié)向用戶講解了TCP效勞器與客戶端的通信過程,并編寫了實例代碼。用戶在學習的過程中,假如對本章實例有興趣,可以將隨書光盤中的相應的實例代碼進展改寫,以到達自己的要求。2.2.4 基于UDP的Sockets編程基于UDP的網(wǎng)絡程序是面向無連接,不可靠的一種應用程序。所以,當程序創(chuàng)立套接字句柄成功以后,便可以直接調(diào)用函數(shù)進展數(shù)據(jù)收發(fā),最后,關(guān)閉套接字對象。在整個過程中,程序都不用調(diào)用任何函數(shù)連接效勞器或者承受客戶端的連接等操作。這種類型的應用程序多用在即時通信中。在UDP中進展數(shù)據(jù)收發(fā)的函數(shù)是sendto()和recvfrom()。函數(shù)原型如下:int sendto (/發(fā)送

33、函數(shù) SOCKET s, /套接字句柄 const char FAR * buf,/數(shù)據(jù)緩沖區(qū) int len,/數(shù)據(jù)的長度 int flags, /一般設(shè)置為0 const struct sockaddr FAR * to,/目的地址構(gòu)造信息 int tolen /目的地址構(gòu)造大小 );int recvfrom (SOCKET s, char FAR* buf, int len, int flags,struct sockaddr FAR* from, int FAR* fromlen);/接收函數(shù)函數(shù)recvfrom()的各個參數(shù)與函數(shù)sendto()的參數(shù)根本一致。參數(shù)from是指向地址

34、構(gòu)造sockaddr_in的指針,表示數(shù)據(jù)發(fā)送方的地址信息。參數(shù)fromlen表示該地址構(gòu)造的大小。1UDP效勞器首先,在VC中創(chuàng)立基于控制臺程序窗口的應用程序,并命名為“UDP效勞器,如下圖。圖2.9 新建UDP效勞器然后,將該工程類型同樣指定為空工程。在新建的工程中新建一個C+源文件,名稱為UDPSever,如下圖。圖2.10 新建C+源文件如今用戶可以在該源文件中編寫UDP效勞器的代碼。代碼如下:編譯并運行程序,如下圖。圖2.11 UDP效勞器啟動界面2UDP客戶端在VC中創(chuàng)立UDP客戶端程序時,與UDP效勞器一樣,工程類型均為空工程。所以,用戶只需在C+源文件中編寫代碼實現(xiàn)UDP客戶端

35、。代碼如下:編譯并運行程序,如下圖。圖2.12 客戶端啟動界面假如用戶先啟動UDP效勞器,再啟動UDP客戶端,那么會在效勞器界面中顯示客戶端連接信息。而客戶端界面中顯示效勞器發(fā)送的信息,如下圖。圖2.13 UDP客戶端與效勞器進展通信在本小節(jié)中,向用戶講解了在VC中使用Winsock函數(shù)進展網(wǎng)絡程序開發(fā),并結(jié)合TCP與UDP實例程序介紹了基于以上兩種協(xié)議的網(wǎng)絡程序編寫方法。2.3 網(wǎng)絡程序?qū)嵗龖糜脩敉ㄟ^本章前面兩節(jié)知識的學習,已經(jīng)對網(wǎng)絡程序的根本原理和程序編寫方法有了進一步理解。在本節(jié)中,將引導用戶在VC中編寫基于對話框的TCP效勞器和TCP客戶端程序并且進展詳細講解。2.3.1 TCP客戶

36、端程序在本小節(jié)中,將向用戶介紹在VC中創(chuàng)立基于對話框形式的TCP客戶端程序界面以及各個功能的實現(xiàn)等。1創(chuàng)立工程在VC中創(chuàng)立一個基于MFC的應用程序工程,并且將該工程名修改為“TCP客戶端程序。步驟如下:1選擇“File|“New命令,翻開“New對話框,如下圖。圖2.14 創(chuàng)立TCP客戶端實例工程2單擊“OK按鈕,進入應用程序向?qū)гO(shè)置的第一步,修改應用程序的類型為“Dialog based,如下圖。圖2.15 修改應用程序類型為根本對話框3單擊“Next按鈕,進入應用程序向?qū)гO(shè)置的第二步,設(shè)置應用程序支持Windows Socket的功能,如下圖。圖2.16 設(shè)置應用程序支持套接字功能4單擊“

37、Finish按鈕,完成工程的創(chuàng)立以及相關(guān)配置。如今,用戶通過應用程序向?qū)б呀?jīng)完成了TCP客戶端工程的創(chuàng)立以及為該工程添加了支持Windows套接字功能等相關(guān)的一些配置。接下來,用戶需要翻開該工程的資源管理器進展程序界面的設(shè)計。2界面設(shè)計當工程創(chuàng)立以后,用戶可以翻開資源管理器查看該工程的對話框資源,如下圖。圖2.17 VC默認情況下的對話框資源用戶可以通過向該對話框面板中添加相應的控件,以到達TCP客戶端程序的根本功能,如下圖。圖2.18 完成設(shè)計后的界面效果其中,用戶添加了多個控件,新添加的控件ID、類型以及作用,如表所示。表2.2 控件ID、類型以及作用控件控件ID控控 件件 類類 型型控件

38、在實例中的作用控件在實例中的作用IDC_ADDR編輯框控件輸入服務器輸入服務器IP地址地址IDC_PORT編輯框控件輸入服務器端口輸入服務器端口IDC_TEXT編輯框控件顯示相關(guān)信息顯示相關(guān)信息IDC_SENDTEXT編輯框控件輸入發(fā)送消息輸入發(fā)送消息IDC_SEND按鈕控件發(fā)送消息按鈕發(fā)送消息按鈕IDC_CONNECT按鈕控件連接服務器連接服務器IDC_STATIC1靜態(tài)控件標識服務器地址標識服務器地址IDC_STATIC2靜態(tài)控件靜態(tài)控件標識服務器端口標識服務器端口3界面初始化TCP客戶端程序啟動時,應該首先連接效勞器以后,用戶才能通過程序發(fā)送消息。所以,該程序初始化時的界面,如下圖。圖2

39、.19 程序初始化界面在界面初始化時,已經(jīng)屏蔽了發(fā)送消息的功能。所以對于應用程序而言,防止了錯誤的發(fā)生。初始化代碼如下:用戶使用函數(shù)GetDlgItem()獲取對應ID控件的指針,然后使用該指針調(diào)用函數(shù)EnableWindow()將控件禁用。函數(shù)EnableWindow()的參數(shù)假如為true,那么表示該控件可以被使用。假如該參數(shù)為false,那么表示該控件被禁用。在界面初始化時,除了初始化界面中的各按鈕之外,還應該對套接字進展初始化。初始化套接字功能的代碼應該在函數(shù)CTCPDlg:OnInitDialog()中實現(xiàn)。代碼如下:在代碼中,用戶在類中聲明了套接字對象和套接字地址構(gòu)造變量。然后,在

40、初始化函數(shù)中創(chuàng)立了TCP套接字s。4功能實現(xiàn)在這一節(jié)中,用戶可以為各個功能控件編寫相應的代碼,以實現(xiàn)其功能。首先,為“連接按鈕添加消息響應函數(shù)。在該控件上雙擊鼠標,將彈出Add Member Function添加成員函數(shù)對話框,如下圖。圖 添加成員函數(shù)對話框在該對話框中,用戶可以將“連接按鈕的消息響應函數(shù)名修改為OnConnect()。函數(shù)代碼如下:將上面的代碼保存以后,進展編譯并運行。假如客戶端連接效勞器成功,那么程序會提示用戶連接成功,如下圖。圖 客戶端連接效勞器成功否那么,程序提示用戶連接效勞器失敗,如下圖。圖2.22 客戶端連接效勞器失敗當客戶端與效勞器連接成功之后,用戶便可以發(fā)送消息

41、到效勞器了。如今,用戶需要為“發(fā)送按鈕添加相應的消息響應函數(shù),并指定該函數(shù)名為OnSend()。該函數(shù)相關(guān)代碼如下:在代碼中,用戶通過調(diào)用函數(shù)send()將消息發(fā)送到指定的效勞器,并將該消息顯示在本地的信息顯示框中,如下圖。圖 客戶端發(fā)送消息作為客戶端,還應該具有接收并顯示效勞器所發(fā)送的消息。在本實例中,將采用異步套接字形式實現(xiàn)該功能。在VC中,將套接字設(shè)置為異步形式,可以調(diào)用函數(shù)WSAAsyncSelect()實現(xiàn)。該函數(shù)原型如下:int WSAAsyncSelect ( SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent );函數(shù)各個參數(shù)

42、如下:參數(shù)s表示需要設(shè)置為異步形式的套接字句柄。參數(shù)hWnd表示接收消息響應的窗口句柄。參數(shù)wMsg表示響應消息標識。參數(shù)lEvent表示發(fā)生在該套接字上的事件,取值如表所示。表 套接字事件部分標識及其意義套接字事件取值套接字事件取值含含 義義 表表 示示套接字事件取值套接字事件取值含含 義義 表表 示示FD_READ套接字上發(fā)生讀取事件FD_ACCEPT套接字上發(fā)生連接事件套接字上發(fā)生連接事件FD_WRITE套接字上發(fā)生寫入事件套接字上發(fā)生寫入事件FD_CLOSE套接字上發(fā)生關(guān)閉事件套接字上發(fā)生關(guān)閉事件首先,在程序初始化函數(shù)OnInitDialog中,將套接字設(shè)置為異步形式。代碼如下:代碼中

43、,將異步套接字處理的事件指定為讀取事件FD_READ,并且將該事件的處理消息指定為WM_SOCKET。該消息是在CTCPDlg類頭文件中定義的自定義消息。代碼如下:用戶自定義消息以及該消息的響應函數(shù)成功后,還需要在消息映射表中將消息與響應函數(shù)相關(guān)聯(lián)。代碼如下:最后,在自定義消息響應函數(shù)OnSocket()中,實現(xiàn)套接字事件的處理。代碼如下:由于在本實例中,僅處理了套接字的讀取事件,所以使用了代碼“if(lParam= FD_READ)。假如用戶需要處理的套接字事件比較多,那么應該在代碼中使用關(guān)鍵字switch進展分類判斷。程序運行效果如下圖。圖2.24 程序運行效果到這里,用戶根本上完成了客戶

44、端應有的功能。在客戶端程序中,需要用戶注意連接效勞器之前,必須首先知道效勞器的IP地址等相關(guān)信息。否那么,程序?qū)o法正確連接到效勞器。2.3.2 TCP效勞器程序在節(jié)中,已經(jīng)向用戶講解了制作TCP客戶端程序的相關(guān)方法。所以,在本節(jié)中將向用戶繼續(xù)講解在VC中怎樣制作TCP效勞器程序。1創(chuàng)立工程在VC中,創(chuàng)立TCP效勞器工程的步驟與創(chuàng)立TCP客戶端工程的步驟一樣,只是在修改工程名稱時應該為“TCP效勞器程序,如下圖。圖2.25 創(chuàng)立TCP效勞器程序工程其他相關(guān)設(shè)置步驟均與TCP客戶端工程的設(shè)置步驟一樣。所以,在本章中不再對此內(nèi)容進展講述,請用戶復習上一節(jié)中的內(nèi)容。注意:用戶在VC中創(chuàng)立實例工程的步驟大體一樣。2界面設(shè)計效勞器工程創(chuàng)立完成之后,用戶可以翻開資源管理器中的對話框資源進展界面的設(shè)計。本實例中,為了完成效勞器的根本功能,所以在對話框面板上添加如表所示的控件,并調(diào)整其位置以及大小。表 控件ID、屬性以及作用用戶將表中所示控件添加到對話框面板中后,應

溫馨提示

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

評論

0/150

提交評論