版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、第第5章章 Socket編程基礎編程基礎在開發(fā)網絡應用程序在開發(fā)網絡應用程序時,最重要的問題就時,最重要的問題就是如何實現(xiàn)不同主機是如何實現(xiàn)不同主機之間的通信。在之間的通信。在TCP/IPTCP/IP網絡環(huán)境中,網絡環(huán)境中,可以使用可以使用SocketSocket接口接口來建立網絡連接、實來建立網絡連接、實現(xiàn)主機之間的數(shù)據傳現(xiàn)主機之間的數(shù)據傳輸。本章將介紹使用輸。本章將介紹使用SocketSocket接口來編寫網接口來編寫網絡應用程序的基本方絡應用程序的基本方法。法。本章知識點本章知識點pSocketSocket協(xié)議原理協(xié)議原理pWinSockWinSock編程基礎編程基礎p面向連接的面向連接
2、的SocketSocket編程編程p面向非連接的面向非連接的SocketSocket編程編程p套接字選項套接字選項5.1 Socket協(xié)議原理協(xié)議原理5.1.1 Socket5.1.1 Socket協(xié)議的工作原理協(xié)議的工作原理5.1.2 Socket5.1.2 Socket的服務方式和類型的服務方式和類型5.1.1 Socket協(xié)議的工作原理協(xié)議的工作原理在網絡應用程序中,實現(xiàn)網絡通信在網絡應用程序中,實現(xiàn)網絡通信的必要條件的必要條件:(1)撥打電話的一方需要知道對方的電話號碼。如果對方使用的是)撥打電話的一方需要知道對方的電話號碼。如果對方使用的是內部電話,則還需要知道分機號碼。而被撥打的電
3、話則不需要知道對內部電話,則還需要知道分機號碼。而被撥打的電話則不需要知道對方的號碼。方的號碼。(2)被撥打的電話號碼必須已經啟用,而且將電話線連接到電話機)被撥打的電話號碼必須已經啟用,而且將電話線連接到電話機上。上。(3)被撥打電話的主人有空閑時間可以接聽電話,如果長期無人接)被撥打電話的主人有空閑時間可以接聽電話,如果長期無人接聽,則會自動掛斷電話。聽,則會自動掛斷電話。(4)雙方必須使用相同的語言進行通話。這一條看似有些多余,但)雙方必須使用相同的語言進行通話。這一條看似有些多余,但如果真的一個說漢語、另一個卻說英語,那也是沒有辦法正常溝通的。如果真的一個說漢語、另一個卻說英語,那也是
4、沒有辦法正常溝通的。(5)在通話過程中,物理線路必須保持通暢,否則電話將會被掛斷。)在通話過程中,物理線路必須保持通暢,否則電話將會被掛斷。(6)在通話過程中,任何一方都可以主動掛斷電話。)在通話過程中,任何一方都可以主動掛斷電話?;诨赥CP協(xié)議的兩個網絡應用程序進行通信的基本過程協(xié)議的兩個網絡應用程序進行通信的基本過程 (1)客戶端(相當于撥打電話的一方)需要了解服務器的地址(相當于電話號碼)。)客戶端(相當于撥打電話的一方)需要了解服務器的地址(相當于電話號碼)。在在TCP/IP網絡環(huán)境中,可以使用網絡環(huán)境中,可以使用IP地址來標識一個主機。但僅僅使用地址來標識一個主機。但僅僅使用IP
5、地址是不夠的,地址是不夠的,如果一臺主機中運行了多個網絡應用程序,那么如何確定與哪個應用程序通信呢。在如果一臺主機中運行了多個網絡應用程序,那么如何確定與哪個應用程序通信呢。在Socket通信過程中借用了通信過程中借用了TCP和和UDP協(xié)議中端口的概念,不同的應用程序可以使用不協(xié)議中端口的概念,不同的應用程序可以使用不同的端口進行通信,這樣一個主機上就可以同時有多個應用程序進行網絡通信了。這同的端口進行通信,這樣一個主機上就可以同時有多個應用程序進行網絡通信了。這有些類似于電話分機的作用。有些類似于電話分機的作用。(2)服務器應用程序必須早于客戶端應用程序啟動,并在指定的)服務器應用程序必須早
6、于客戶端應用程序啟動,并在指定的IP地址和端口上執(zhí)行地址和端口上執(zhí)行監(jiān)聽操作。如果該端口被其他應用程序所占用,則服務器應用程序無法正常啟動。服監(jiān)聽操作。如果該端口被其他應用程序所占用,則服務器應用程序無法正常啟動。服務器處于監(jiān)聽狀態(tài)就類似于電話接通電話線、等待撥打的狀態(tài)。務器處于監(jiān)聽狀態(tài)就類似于電話接通電話線、等待撥打的狀態(tài)。(3)客戶端在申請發(fā)送數(shù)據時,服務器端應用程序必須有足夠的時間響應才能進行正)客戶端在申請發(fā)送數(shù)據時,服務器端應用程序必須有足夠的時間響應才能進行正常通信。否則,就好像電話已經響了,但卻無人接聽一樣。在通常情況下,服務器應常通信。否則,就好像電話已經響了,但卻無人接聽一樣
7、。在通常情況下,服務器應用程序都需要具備同時處理多個客戶端請求的能力,如果服務器應用程序設計得不合用程序都需要具備同時處理多個客戶端請求的能力,如果服務器應用程序設計得不合理或者客戶端的訪問量過大,都有可能導致無法及時響應客戶端的情況。理或者客戶端的訪問量過大,都有可能導致無法及時響應客戶端的情況。(4)使用)使用Socket協(xié)議進行通信的雙方還必須使用相同的通信協(xié)議,協(xié)議進行通信的雙方還必須使用相同的通信協(xié)議,Socket支持的底支持的底層通信協(xié)議包括層通信協(xié)議包括TCP和和UDP兩種。在通信過程中,雙方還必須采用相同的字符編碼格兩種。在通信過程中,雙方還必須采用相同的字符編碼格式,而且按照
8、雙方約定的方式進行通信。這就好像在通電話的時候雙方都采用對方能式,而且按照雙方約定的方式進行通信。這就好像在通電話的時候雙方都采用對方能理解的語言進行溝通一樣。理解的語言進行溝通一樣。(5)在通信過程中,物理網絡必須保持暢通,否則通信將會中斷。)在通信過程中,物理網絡必須保持暢通,否則通信將會中斷。(6)通信結束后,服務器端和客戶端應用程序都可以中斷它們之間的連接。)通信結束后,服務器端和客戶端應用程序都可以中斷它們之間的連接。Socket編程的層次結構編程的層次結構5.1.2 Socket的服務方式和類型的服務方式和類型p在在SocketSocket通信中,套接字分為通信中,套接字分為3 3
9、種類型種類型,即流式套接字(,即流式套接字(SOCK_STREAMSOCK_STREAM)、數(shù))、數(shù)據報式套接字(據報式套接字(SOCK_DGRAMSOCK_DGRAM)和原始套)和原始套接字(接字(SOCK_RAWSOCK_RAW)。)。1流式套接字流式套接字p 流式套接字提供面向連接的、可靠的數(shù)據傳輸服務流式套接字提供面向連接的、可靠的數(shù)據傳輸服務,可以無差錯地發(fā)送數(shù)據。傳輸數(shù)據可以是雙向的,可以無差錯地發(fā)送數(shù)據。傳輸數(shù)據可以是雙向的字節(jié)流,即應用程序采用全雙工方式,通過套接字字節(jié)流,即應用程序采用全雙工方式,通過套接字同時傳輸和接收數(shù)據。同時傳輸和接收數(shù)據。p 應用程序可以通過流傳遞有序
10、的、不重復的數(shù)據。應用程序可以通過流傳遞有序的、不重復的數(shù)據。所謂所謂“有序有序”指數(shù)據包按發(fā)送順序送達目的地址,指數(shù)據包按發(fā)送順序送達目的地址,所謂所謂“不重復不重復”指一個特定的數(shù)據包只能獲取一次指一個特定的數(shù)據包只能獲取一次。p 如果必須保證數(shù)據能夠可靠地傳送到目的地、并且如果必須保證數(shù)據能夠可靠地傳送到目的地、并且數(shù)據量很大時,可以采用流式套接字傳輸數(shù)據。文數(shù)據量很大時,可以采用流式套接字傳輸數(shù)據。文件傳輸協(xié)議(件傳輸協(xié)議(FTPFTP)即采用流式套接字傳輸數(shù)據。)即采用流式套接字傳輸數(shù)據。2數(shù)據報式套接字數(shù)據報式套接字比較項目比較項目流式套接字流式套接字數(shù)據報式套接字數(shù)據報式套接字建
11、立和釋放連接保證數(shù)據到達按發(fā)送順序接收數(shù)據通訊數(shù)據包含完整的目的地址信息3原始套接字原始套接字p原始套接字是公開的套接字編程接口,原始套接字是公開的套接字編程接口,使用它可以在使用它可以在IPIP層上對套接字進行編程層上對套接字進行編程,發(fā)送和接收,發(fā)送和接收IPIP層上的原始數(shù)據包,例層上的原始數(shù)據包,例如如ICMPICMP、TCPTCP和和UDPUDP等協(xié)議的數(shù)據包。等協(xié)議的數(shù)據包。5.2 WinSock編程基礎編程基礎5.2.1 5.2.1 構建構建WinSockWinSock應用程序框架應用程序框架5.2.2 IP5.2.2 IP地址的表示形式地址的表示形式5.2.1 構建構建WinS
12、ock應用程序框架應用程序框架p WinSockWinSock包含兩個主要的版本,即包含兩個主要的版本,即WinSock1WinSock1和和WinSock2WinSock2。在使用。在使用WinSock 1.1WinSock 1.1時,需要引用頭文件時,需要引用頭文件winsock.hwinsock.h和庫文件和庫文件wsock32.libwsock32.lib,代碼如下:,代碼如下:#include #include #pragma comment(lib, wsock32.lib) #pragma comment(lib, wsock32.lib) p 在在Visual Studio 2
13、005Visual Studio 2005中,通常使用中,通常使用WinSock 2.2WinSock 2.2實現(xiàn)網絡通信的實現(xiàn)網絡通信的功能,則需要引用頭文件功能,則需要引用頭文件winsock2.hwinsock2.h和庫文件和庫文件ws2_32.libws2_32.lib,代碼,代碼如下:如下:#include #include #pragma comment(lib, ws2_32.lib)#pragma comment(lib, ws2_32.lib)使用使用WinSock 2.2實現(xiàn)網絡通信的應用程序框架實現(xiàn)網絡通信的應用程序框架#include #include #pragma
14、comment(lib, ws2_32.lib)#pragma comment(lib, ws2_32.lib)/ / 主函數(shù)主函數(shù)int _tmain(int argc, _TCHARint _tmain(int argc, _TCHAR* * argv) argv) / WSADATA / WSADATA 結構體主要包含了系統(tǒng)所支持的結構體主要包含了系統(tǒng)所支持的WinsockWinsock版本信息版本信息 WSADATA wsaData; WSADATA wsaData; / / 初始化初始化Winsock 2.2Winsock 2.2if( WSAStartup( MAKEWORD(2,
15、2), &wsaData) != 0 ) if( WSAStartup( MAKEWORD(2,2), &wsaData) != 0 ) printf( WSAStartup printf( WSAStartup 無法初始化!無法初始化!); ); return 0; return 0; / / 使用使用WinSockWinSock實現(xiàn)網絡通信實現(xiàn)網絡通信/ ./ ./ / 最后應該做一些清除工作最后應該做一些清除工作 if( WSACleanup() = SOCKET_ERROR ) if( WSACleanup() = SOCKET_ERROR ) printf( WSAC
16、leanup printf( WSACleanup 出錯!出錯!); ); return 0;return 0; 結構體結構體WSADATA用于存儲調用用于存儲調用WSAStartup()WSAStartup()函數(shù)后返回的函數(shù)后返回的Windows SocketWindows Socket數(shù)據數(shù)據。typedef struct WSAData typedef struct WSAData WORD wVersion; WORD wVersion; WORD wHighVersion; WORD wHighVersion;#ifdef _WIN64#ifdef _WIN64 unsigned
17、short iMaxSockets; unsigned short iMaxSockets; unsigned short iMaxUdpDg; unsigned short iMaxUdpDg; char FAR char FAR * * lpVendorInfo; lpVendorInfo; char szDescriptionWSADESCRIPTION_LEN+1; char szDescriptionWSADESCRIPTION_LEN+1; char szSystemStatusWSASYS_STATUS_LEN+1; char szSystemStatusWSASYS_STATU
18、S_LEN+1;#else#else char szDescriptionWSADESCRIPTION_LEN+1; char szDescriptionWSADESCRIPTION_LEN+1; char szSystemStatusWSASYS_STATUS_LEN+1; char szSystemStatusWSASYS_STATUS_LEN+1; unsigned short iMaxSockets; unsigned short iMaxSockets; unsigned short iMaxUdpDg; unsigned short iMaxUdpDg; char FAR char
19、 FAR * * lpVendorInfo; lpVendorInfo;#endif#endif WSADATA, FAR WSADATA, FAR * * LPWSADATA; LPWSADATA;結構體結構體WSADATA的各字段說明的各字段說明字段字段含義含義wVersionWindows Sockets DLL期望調用者使用的Windows Sockets規(guī)范的版本,為WORD類型。高位字節(jié)中存儲副版本號,低位字節(jié)中存儲高版本號??梢允褂肕AKEWORD()函數(shù)返回該值,例如MAKEWORD(2, 2)wHighVersionWindows Sockets DLL可以支持的Window
20、s Sockets規(guī)范的最高版本szDescription以null結尾的ASCII字符串。Windows Sockets DLL將對Windows Sockets實現(xiàn)的描述復制到該字符串中,最多可以包含256個字符szSystemStatus以null結尾的ASCII字符串。Windows Sockets DLL將有關狀態(tài)或配置信息復制到該字符串中iMaxSockets單個進程可以打開的最大套接口數(shù)量。Windows Sockets可以提供一個全局的套接口,為每個進程分配套接口資源。程序員可以使用該多好數(shù)字作為Windows Sockets是否可以被應用程序使用的原始依據iMaxUdpDgW
21、indows Sockets應用程序能夠發(fā)送或接收的最大UDP數(shù)據包大小,單位為字節(jié)。如果實現(xiàn)方式沒有限制,則iMaxUdpDg等于0lpVendorInfo指向銷售商數(shù)據結構的指針WSAStartup()函數(shù)函數(shù)int WSAStartup(int WSAStartup( IN WORD wVersionRequested, IN WORD wVersionRequested, OUT LPWSADATA lpWSAData OUT LPWSADATA lpWSAData ); );參數(shù)說明如下:參數(shù)說明如下:p wVersionRequestedwVersionRequested,Wind
22、ows Sockets DLLWindows Sockets DLL規(guī)定調用者可以使規(guī)定調用者可以使用的用的Windows SocketsWindows Sockets規(guī)范的版本,為規(guī)范的版本,為WORDWORD類型。高位字節(jié)中存類型。高位字節(jié)中存儲副版本號,低位字節(jié)中存儲高版本號??梢允褂脙Ω卑姹咎?,低位字節(jié)中存儲高版本號??梢允褂肕AKEWORD()MAKEWORD()函函數(shù)返回該值,例如數(shù)返回該值,例如MAKEWORD(2, 2)MAKEWORD(2, 2)。p lpWSADatalpWSAData,指向,指向WSADATAWSADATA結構體的指針,用于接收結構體的指針,用于接收Win
23、dows Windows SocketsSockets執(zhí)行的數(shù)據。執(zhí)行的數(shù)據。【例【例5.1】p通過一個控制臺應用程序實例來演示初始化通過一個控制臺應用程序實例來演示初始化Windows SocketsWindows Sockets并返回結果的方法。假定項目名稱為并返回結果的方法。假定項目名稱為WSAStartupWSAStartup,主程序,主程序WSAStartup.cppWSAStartup.cpp的代碼如下:的代碼如下:#include stdafx.h#include stdafx.h#include #include #pragma comment(lib, ws2_32.lib)
24、#pragma comment(lib, ws2_32.lib)#include #include int _tmain(int argc, _TCHARint _tmain(int argc, _TCHAR* * argv) argv) / WSADATA / WSADATA 結構體主要包含了系統(tǒng)所支持的結構體主要包含了系統(tǒng)所支持的WinsockWinsock版本信息版本信息 WSADATA wsaData; WSADATA wsaData; / / 初始化初始化Winsock 2.2Winsock 2.2 if( WSAStartup( MAKEWORD(2,2), &wsaDat
25、a) != 0 ) if( WSAStartup( MAKEWORD(2,2), &wsaData) != 0 ) printf( WSAStartup printf( WSAStartup 無法初始化!無法初始化!); ); return 0; return 0; / / 顯示顯示wsaDatawsaData中的數(shù)據中的數(shù)據 printf(Version: %d.%dn, LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion); printf(Version: %d.%dn, LOBYTE(wsaData.wVersion), HIBYT
26、E(wsaData.wVersion); printf(High Version: %d.%dn, LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion); printf(High Version: %d.%dn, LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion); printf(Description: %sn, wsaData.szDescription); printf(Description: %sn, wsaData.szDescription); pri
27、ntf(System Status: %s, wsaData.szSystemStatus); printf(System Status: %s, wsaData.szSystemStatus); / / 最后應該做一些清除工作最后應該做一些清除工作 if( WSACleanup() = SOCKET_ERROR ) if( WSACleanup() = SOCKET_ERROR ) printf( WSACleanup printf( WSACleanup 出錯!出錯!); ); printf(nn); printf(nn); system(pause); system(pause); re
28、turn 0; return 0; 例例 IP地址的表示形式地址的表示形式p 對于網絡管理員或普通用戶而言,對于網絡管理員或普通用戶而言,IPIP地址常用點分法地址常用點分法來表示。即使用來表示。即使用4 4個個02550255的整數(shù)表示的整數(shù)表示IPIP地址,每個整地址,每個整數(shù)之間使用小數(shù)點(數(shù)之間使用小數(shù)點(. .)分隔,例如)分隔,例如。在。在第第3 3章中已經對章中已經對IPIP地址的這種表示形式做了詳細的介地址的這種表示形式做了詳細的介紹。紹。p 但是在計算機中并不使用點分法來保存但是在計算機中并不使用點分法來保存IPIP
29、地址,因為地址,因為這樣會浪費存儲空間,而且不便于根據這樣會浪費存儲空間,而且不便于根據IPIP地址和子網地址和子網掩碼計算子網的信息。事實上,在計算機中使用無符掩碼計算子網的信息。事實上,在計算機中使用無符號長整數(shù)(號長整數(shù)(unsigned longunsigned long)來存儲和表示)來存儲和表示IPIP地址,地址,而且分為網絡字節(jié)順序(而且分為網絡字節(jié)順序(NBONBO,Network Byte OrderNetwork Byte Order)和主機字節(jié)順序()和主機字節(jié)順序(HBOHBO,Host Byte OrderHost Byte Order)兩種格)兩種格式。在網絡程序設
30、計時必須了解式。在網絡程序設計時必須了解IPIP地址的這兩種表示地址的這兩種表示形式。形式。1網絡字節(jié)順序格式網絡字節(jié)順序格式p在網絡傳輸過程中,在網絡傳輸過程中,IPIP地址被保存為地址被保存為3232位二進制數(shù)。位二進制數(shù)。TCP/IPTCP/IP協(xié)議規(guī)定,在低協(xié)議規(guī)定,在低位存儲地址中保存數(shù)據的高位字節(jié),這種存儲順序格式被稱為網絡字節(jié)順序。位存儲地址中保存數(shù)據的高位字節(jié),這種存儲順序格式被稱為網絡字節(jié)順序。數(shù)據按照數(shù)據按照3232位二進制數(shù)為一組進行傳輸,因為采用網絡字節(jié)順序,所以數(shù)據位二進制數(shù)為一組進行傳輸,因為采用網絡字節(jié)順序,所以數(shù)據的傳輸順序是由高位至低位進行的。的傳輸順序是由高
31、位至低位進行的。p在在Visual C+Visual C+中使用結構體中使用結構體in_addrin_addr來保存網絡字節(jié)順序格式的來保存網絡字節(jié)順序格式的IPIP地址,它的地址,它的定義代碼如下:定義代碼如下:struct in_addr struct in_addr union union struct u_char s_b1,s_b2,s_b3,s_b4; S_un_b; struct u_char s_b1,s_b2,s_b3,s_b4; S_un_b; struct u_short s_w1,s_w2; S_un_w; struct u_short s_w1,s_w2; S_un_
32、w; u_long S_addr; u_long S_addr; S_un; S_un;p參數(shù)說明如下:參數(shù)說明如下:pS_un_bS_un_b,由,由4 4個個u_charu_char變量組成的主機格式變量組成的主機格式IPIP地址。地址。pS_un_wS_un_w,由,由2 2個個u_shortu_short變量組成的主機格式變量組成的主機格式IPIP地址。地址。pS_addrS_addr,以,以u_longu_long變量表示的主機格式變量表示的主機格式IPIP地址地址inet_addr()pinet_addr()函數(shù)的功能是將點分法函數(shù)的功能是將點分法IP地址字符串轉換為地址字符串轉換
33、為in_addr結構體中的結構體中的IP地址格式,它的語法如下:地址格式,它的語法如下:unsigned long inet_addr( const char* cp );p參數(shù)參數(shù)cp表示點分法表示點分法IP地址字符串。如果調用地址字符串。如果調用inet_addr()函數(shù)函數(shù)時沒有出現(xiàn)錯誤,則函數(shù)返回時沒有出現(xiàn)錯誤,則函數(shù)返回unsignedlong類型的網絡字節(jié)類型的網絡字節(jié)順序格式順序格式IP地址;如果參數(shù)地址;如果參數(shù)cp不是有效的不是有效的IP地址字符串,則地址字符串,則inet_addr()函數(shù)返回函數(shù)返回INADDR_NONE。inet_ntoa()p inet_ntoa()i
34、net_ntoa()函數(shù)的功能是將函數(shù)的功能是將in_addrin_addr結構體中的結構體中的IPIP地址轉換為點地址轉換為點分法分法IPIP地址字符串,它的語法如下:地址字符串,它的語法如下:char FARchar FAR* * inet_ntoa( inet_ntoa( struct in_addr in struct in_addr in ););p 參數(shù)參數(shù)inin是是in_addrin_addr結構體類型,表示要進行轉換的結構體類型,表示要進行轉換的IPIP地址,返回結地址,返回結果為果為charchar* *類型的類型的IPIP地址。地址。2主機字節(jié)順序格式主機字節(jié)順序格式p不
35、同的主機在對不同的主機在對IPIP地址進行存儲時使用的格地址進行存儲時使用的格式也不同。有些操作系統(tǒng)的式也不同。有些操作系統(tǒng)的IPIP地址存儲順序地址存儲順序與網絡字節(jié)順序格式相同,而與網絡字節(jié)順序格式相同,而Intel x86Intel x86系列系列主機的主機字節(jié)順序格式則與網絡字節(jié)順序主機的主機字節(jié)順序格式則與網絡字節(jié)順序格式正好相反。格式正好相反。p可以使用可以使用htonl()htonl()、htons()htons()、ntohl()ntohl()和和ntohs()ntohs()這這4 4個函數(shù)來實現(xiàn)主機字節(jié)順序格式個函數(shù)來實現(xiàn)主機字節(jié)順序格式和網絡字節(jié)順序格式之間的轉換。和網絡字
36、節(jié)順序格式之間的轉換。 htonl()函數(shù)函數(shù)phtonl()htonl()函數(shù)的功能是將函數(shù)的功能是將u_longu_long類型的類型的主機字節(jié)順序格式主機字節(jié)順序格式IPIP地址轉換為地址轉換為TCP/IPTCP/IP網絡字節(jié)順序格式,它的語法網絡字節(jié)順序格式,它的語法如下:如下:u_long htonl(u_long htonl( u_long hostlong u_long hostlong ););htons()函數(shù)函數(shù)p htons()htons()函數(shù)的功能是將函數(shù)的功能是將u_shortu_short類型的主機字節(jié)順序類型的主機字節(jié)順序格式格式IPIP地址轉換為地址轉換為TC
37、P/IPTCP/IP網絡字節(jié)順序格式,它的語網絡字節(jié)順序格式,它的語法如下:法如下:u_short htons(u_short htons( u_short hostshort u_short hostshort );); ntohl()函數(shù)函數(shù)p ntohl()ntohl()函數(shù)的功能是將函數(shù)的功能是將u_longu_long類型的類型的TCP/IPTCP/IP網絡字節(jié)網絡字節(jié)順序格式順序格式IPIP地址轉換為主機字節(jié)順序格式,它的語法地址轉換為主機字節(jié)順序格式,它的語法如下:如下:u_long ntohl(u_long ntohl( u_long netlong u_long netlon
38、g ););ntohs()函數(shù)函數(shù)p ntohs()ntohs()函數(shù)的功能是將函數(shù)的功能是將u_shortu_short類型的類型的TCP/IPTCP/IP網絡字節(jié)網絡字節(jié)順序格式順序格式IPIP地址轉換為主機字節(jié)順序格式,它的語法如地址轉換為主機字節(jié)順序格式,它的語法如下:下:u_short ntohs(u_short ntohs( u_short netshort u_short netshort ););5.3 面向連接的面向連接的Socket編程編程5.3.1 5.3.1 面向連接的面向連接的SocketSocket通信流程通信流程5.3.2 socket()5.3.2 socket
39、()函數(shù)函數(shù)5.3.3 bind()5.3.3 bind()函數(shù)函數(shù)5.3.4 listen()5.3.4 listen()函數(shù)函數(shù)5.3.5 accept()5.3.5 accept()函數(shù)函數(shù)5.3.6 recv()5.3.6 recv()函數(shù)函數(shù)5.3.7 send()5.3.7 send()函數(shù)函數(shù)5.3.8 closesocket()5.3.8 closesocket()函數(shù)函數(shù)5.3.9 shutdown()5.3.9 shutdown()函數(shù)函數(shù)5.3.10 connect()5.3.10 connect()函數(shù)函數(shù)5.3.11 TCP5.3.11 TCP套接字服務器應用程序編程
40、實例套接字服務器應用程序編程實例5.3.12 TCP5.3.12 TCP套接字客戶端應用程序編程實例套接字客戶端應用程序編程實例5.3.1 面向連接的面向連接的Socket通信流程通信流程服務器程序中調用的服務器程序中調用的Socket函數(shù)函數(shù)(1 1)調用)調用WSAStartup()WSAStartup()函數(shù)加載函數(shù)加載Windows SocketsWindows Sockets動態(tài)庫,然后調用動態(tài)庫,然后調用socket()socket()函數(shù)創(chuàng)建一個流式套接字,返回套接字號函數(shù)創(chuàng)建一個流式套接字,返回套接字號s s。(2 2)調用)調用bind()bind()函數(shù)將套接字函數(shù)將套接字
41、s s綁定到一個已知的地址,通常為本地綁定到一個已知的地址,通常為本地IPIP地址。地址。(3 3)調用)調用listen()listen()函數(shù)將套接字函數(shù)將套接字s s設置為監(jiān)聽模式,準備好接收來自各設置為監(jiān)聽模式,準備好接收來自各個客戶機的連接請求。個客戶機的連接請求。(4 4)調用)調用accept()accept()函數(shù)等待接受客戶端的連接請求。函數(shù)等待接受客戶端的連接請求。(5 5)如果接收到客戶端的請求,則)如果接收到客戶端的請求,則accept()accept()函數(shù)返回,得到新的套接函數(shù)返回,得到新的套接字字nsns。(6 6)調用)調用recv()recv()函數(shù)接收來自客
42、戶端的數(shù)據,調用函數(shù)接收來自客戶端的數(shù)據,調用send()send()函數(shù)向客戶函數(shù)向客戶端發(fā)送數(shù)據。端發(fā)送數(shù)據。(7 7)與客戶端的通信結束后,服務器程序可以調用)與客戶端的通信結束后,服務器程序可以調用shutdown()shutdown()函數(shù)通函數(shù)通知對方不再發(fā)送或接收數(shù)據,也可以由客戶端程序斷開連接。斷開連接知對方不再發(fā)送或接收數(shù)據,也可以由客戶端程序斷開連接。斷開連接后,服務器進程調用后,服務器進程調用closesocket()closesocket()函數(shù)關閉套接字函數(shù)關閉套接字nsns。此后服務器程。此后服務器程序返回第序返回第4 4步,繼續(xù)等待客戶端進程的連接。步,繼續(xù)等待客
43、戶端進程的連接。(8 8)如果要退出服務器程序,則調用)如果要退出服務器程序,則調用closesocket()closesocket()函數(shù)關閉最初的套函數(shù)關閉最初的套接字接字s s??蛻舳顺绦蛟诿恳徊襟E中使用的函數(shù)客戶端程序在每一步驟中使用的函數(shù)(1)調用)調用WSAStartup()函數(shù)加載函數(shù)加載Windows Sockets動動態(tài)庫,然后調用態(tài)庫,然后調用socket()函數(shù)創(chuàng)建一個流式套接字,返回函數(shù)創(chuàng)建一個流式套接字,返回套接字號套接字號s。(2)調用)調用connect()函數(shù)將套接字函數(shù)將套接字s連接到服務器。連接到服務器。(3)調用)調用send()函數(shù)向服務器發(fā)送數(shù)據,調用
44、函數(shù)向服務器發(fā)送數(shù)據,調用recv()函數(shù)函數(shù)接收來自服務器的數(shù)據。接收來自服務器的數(shù)據。(4)與服務器的通信結束后,客戶端程序可以調用)與服務器的通信結束后,客戶端程序可以調用shutdown()函數(shù)通知對方不再發(fā)送或接收數(shù)據,也可以函數(shù)通知對方不再發(fā)送或接收數(shù)據,也可以由服務器程序斷開連接。斷開連接后,客戶端進程調用由服務器程序斷開連接。斷開連接后,客戶端進程調用closesocket()函數(shù)關閉套接字。函數(shù)關閉套接字。5.3.2 socket()函數(shù)函數(shù)p socket()socket()函數(shù)用于創(chuàng)建與指定的服務提供者綁定套接字,它的函數(shù)用于創(chuàng)建與指定的服務提供者綁定套接字,它的語法如下
45、:語法如下:SOCKET socket(SOCKET socket( int af, int af, int type, int type, int protocol int protocol ););參數(shù)說明如下:參數(shù)說明如下:p afaf,指定協(xié)議的地址家族,通常使用,指定協(xié)議的地址家族,通常使用AF_INETAF_INET。p typetype,指定套接字的類型,具體取值如表,指定套接字的類型,具體取值如表5.45.4所示。所示。p protocolprotocol,套接字使用的協(xié)議。,套接字使用的協(xié)議。套接字類型套接字類型套接字類型套接字類型說說 明明SOCK_STREAM提供順序、可
46、靠、雙向和面向連接的字節(jié)流數(shù)據傳輸機制,使用TCP協(xié)議SOCK_DGRAM支持面向無連接的數(shù)據報,使用UDP協(xié)議SOCK_RAW原始套接字,可以用于接收本機網卡上的數(shù)據幀或者數(shù)據包【例【例5.2】使用使用socket()socket()函數(shù)創(chuàng)建一個函數(shù)創(chuàng)建一個TCPTCP套接字,代碼如下:套接字,代碼如下:/ WSADATA / WSADATA 結構體主要包含了系統(tǒng)所支持的結構體主要包含了系統(tǒng)所支持的WinsockWinsock版本信息版本信息WSADATA wsaData; WSADATA wsaData; / / 初始化初始化Winsock 2.2Winsock 2.2if( WSASta
47、rtup( MAKEWORD(2,2), &wsaData) != 0 ) if( WSAStartup( MAKEWORD(2,2), &wsaData) != 0 ) printf( WSAStartup printf( WSAStartup 無法初始化!無法初始化!); ); return 0; return 0; / / 顯示顯示wsaDatawsaData中的數(shù)據中的數(shù)據printf(Version: %d.%dn, LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion);printf(Version: %d.%dn, L
48、OBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion);printf(High Version: %d.%dn, LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion);printf(High Version: %d.%dn, LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion);printf(Description: %sn, wsaData.szDescription);printf(Description: %sn, w
49、saData.szDescription);printf(System Status: %s, wsaData.szSystemStatus);printf(System Status: %s, wsaData.szSystemStatus);/ / 創(chuàng)建創(chuàng)建TCPTCP套接字套接字SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if(s = INVALID_SOCKET)if(s = INVALID_SOCKET) printf(
50、socket error!);printf(socket error!); / / 使用使用TCPTCP套接字套接字s s進行通信進行通信/ / 最后應該做一些清除工作最后應該做一些清除工作 if( WSACleanup() = SOCKET_ERROR ) if( WSACleanup() = SOCKET_ERROR ) printf( WSACleanup printf( WSACleanup 出錯!出錯!););5.3.3 bind()函數(shù)函數(shù)p bind()bind()函數(shù)可以將本地地址與一個套接字綁定在一起,它的語法函數(shù)可以將本地地址與一個套接字綁定在一起,它的語法如下:如下:in
51、t bind(int bind( SOCKET s, SOCKET s, const struct sockaddr FAR const struct sockaddr FAR* * name, name, int namelen int namelen ););p 參數(shù)說明如下:參數(shù)說明如下:p s s,標識一個未綁定的套接字的描述符。,標識一個未綁定的套接字的描述符。p namename,綁定到套接字,綁定到套接字s s的的sockaddrsockaddr結構體地址。結構體地址。p namelennamelen,參數(shù),參數(shù)namename的長度。的長度。p 如果未發(fā)生錯誤,則函數(shù)返回如果未
52、發(fā)生錯誤,則函數(shù)返回0 0;否則返回;否則返回SOCKET_ERRORSOCKET_ERROR?!纠纠?.3】使用使用bind()bind()函數(shù)綁定函數(shù)綁定TCPTCP套接字到本地地址的套接字到本地地址的90019001端口,代碼如下:端口,代碼如下:/ / 初始化初始化Winsock 2.2Winsock 2.2/ / / / 創(chuàng)建創(chuàng)建TCPTCP套接字套接字/ / / / 指定綁定的地址指定綁定的地址struct sockaddr_in addr;struct sockaddr_in addr;/ / 地址的長度地址的長度int addr_len = sizeof(struct soc
53、kaddr_in);int addr_len = sizeof(struct sockaddr_in);int port = 9901;int port = 9901;/ / 端口號端口號int errCode;int errCode;/ / 錯誤代碼錯誤代碼【例【例5.3】/ / 定義服務器地址定義服務器地址addr.sin_family =AF_INET;addr.sin_family =AF_INET;/ / 地址家族地址家族addr.sin_port = htons(port); / addr.sin_port = htons(port); / 端口端口addr.sin_addr.s_
54、addr = htonl(INADDR_ANY);addr.sin_addr.s_addr = htonl(INADDR_ANY);/ / 地址地址/ / 綁定到套接字綁定到套接字errCode = bind(s, (SOCKADDRerrCode = bind(s, (SOCKADDR* *)&addr, addr_len);)&addr, addr_len);if(errCode = SOCKET_ERROR)if(errCode = SOCKET_ERROR) printf(bind error!);printf(bind error!);exit(1);exit(1);
55、 / / 監(jiān)聽和接收數(shù)據監(jiān)聽和接收數(shù)據/ / 最后應該做一些清除工作最后應該做一些清除工作/ / 5.3.4 listen()函數(shù)函數(shù)p listen()listen()函數(shù)可以將套接字設置為監(jiān)聽接入連接的狀態(tài),它的語函數(shù)可以將套接字設置為監(jiān)聽接入連接的狀態(tài),它的語法如下:法如下:int listen(int listen( SOCKET s, SOCKET s, int backlog int backlog ););參數(shù)說明如下:參數(shù)說明如下:p s s,指定一個已經綁定(執(zhí)行了,指定一個已經綁定(執(zhí)行了bind()bind()函數(shù))但尚未連接的套接字函數(shù))但尚未連接的套接字。p back
56、logbacklog,指定等待連接隊列的最大長度。,指定等待連接隊列的最大長度。如果函數(shù)執(zhí)行成功,則返回如果函數(shù)執(zhí)行成功,則返回0 0;否則返回;否則返回SOCKET_ERRORSOCKET_ERROR??梢哉{用??梢哉{用WSAGetLastError()WSAGetLastError()函數(shù)獲取錯誤代碼函數(shù)獲取錯誤代碼 調用調用listen()函數(shù)的錯誤代碼函數(shù)的錯誤代碼錯誤代碼錯誤代碼說說 明明WSANOTINITIALISED在 調 用 l i s t e n ( ) 函 數(shù) 之 前 沒 有 成 功 調 用WSAStartup()函數(shù)對WinSock進行初始化WSAENETDOWN網絡子
57、系統(tǒng)故障WSAEADDRINUSE本地套接字地址已經使用,并且標識為不可重用WSAEINPROGRESS存在一個阻塞的Windows Sockets 1.1調用,或者Windows Sockets還在處理一個回調函數(shù)WSAEINVAL套接字尚未綁定WSAEISCONN套接字已經連接WSAEMFILE沒有有效的套接字描述符WSAENOBUFS沒有足夠的緩沖區(qū)空間WSAENOTSOCK指定描述符并不是一個套接字WSAEOPNOTSUPP引用的套接字并不支持listen操作【例【例5.4】p使用使用listen()listen()函數(shù)設置套接字的監(jiān)聽狀態(tài),代碼如下:函數(shù)設置套接字的監(jiān)聽狀態(tài),代碼如下
58、:/ / 初始化初始化Winsock 2.2Winsock 2.2/ / 創(chuàng)建創(chuàng)建TCPTCP套接字套接字/ / 指定綁定的地址指定綁定的地址/ / 定義服務器地址定義服務器地址/ / 綁定到套接字綁定到套接字/ / 切換到監(jiān)聽狀態(tài)切換到監(jiān)聽狀態(tài)errCode = listen(s, 3);errCode = listen(s, 3);if(errCode = SOCKET_ERROR)if(errCode = SOCKET_ERROR) printf(listen error!);printf(listen error!);exit(1);exit(1); / / 監(jiān)聽和接收數(shù)據監(jiān)聽和接收數(shù)
59、據/ / 最后應該做一些清除工作最后應該做一些清除工作5.3.5 accept()函數(shù)函數(shù)p 在服務器端調用在服務器端調用listen()listen()函數(shù)監(jiān)聽接入連接后,可以調用函數(shù)監(jiān)聽接入連接后,可以調用accept()accept()函數(shù)函數(shù)來等待接受連接請求。來等待接受連接請求。accept()accept()函數(shù)的語法如下:函數(shù)的語法如下:SOCKET accept(SOCKET accept( SOCKET s, SOCKET s, struct sockaddr FAR struct sockaddr FAR* * addr, addr, int FAR int FAR* *
60、addrlen addrlen ););參數(shù)說明如下:參數(shù)說明如下:p s s,通過調用,通過調用listen()listen()函數(shù)設置為監(jiān)聽狀態(tài)的套接字。函數(shù)設置為監(jiān)聽狀態(tài)的套接字。p addraddr,輸出參數(shù),用于接收接入地址信息。這是一個可選參數(shù),如果不,輸出參數(shù),用于接收接入地址信息。這是一個可選參數(shù),如果不關注接入地址,則可以使用關注接入地址,則可以使用NULLNULL。p addrlenaddrlen,輸出參數(shù),指定接入地址的長度。這也是一個可選參數(shù)。,輸出參數(shù),指定接入地址的長度。這也是一個可選參數(shù)。p 如果函數(shù)調用成功,則返回一個新建的套接字的句柄,該套接字用于實如果函數(shù)調用成功,則返回一個新建的套接字的句柄,該套接字用于實現(xiàn)服務器和客戶端之前的通信。如果調用
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 臨時用電事故應對方案
- 金融行業(yè)客戶服務制度
- 懷化學院《物理光學實驗》2022-2023學年第一學期期末試卷
- 學前教育研究方法學習通超星期末考試答案章節(jié)答案2024年
- 2024營業(yè)執(zhí)照房屋租賃合同模板
- 懷化學院《HTML5應用開發(fā)》2022-2023學年期末試卷
- 華中師范大學《中國古典舞風格》2022-2023學年第一學期期末試卷
- 學校教室墻面抹灰施工方案
- 情報學理論方法系列講座之十
- 混凝土重力壩課程設計
- 六年級下冊音樂教案第六單元《畢業(yè)歌》人教新課標
- 世界咖啡介紹 PPT
- 中醫(yī)藥膳學全套課件
- 馬王堆出土文物藝術欣賞-課件
- 初中語文人教六年級下冊《專題閱讀:概括主要事件》PPT
- 13、停電停水等突發(fā)事件的應急預案以及消防制度
- DB42T1811-2022西瓜設施育苗技術規(guī)程
- 早教托育園招商加盟商業(yè)計劃書
- 醫(yī)療HRP整體解決方案課件
- 分布式光伏安裝清包合同
- 四機廠介紹企業(yè)介紹
評論
0/150
提交評論