




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第二章Winsock編程接口Winsock是Windows下網(wǎng)絡(luò)編程的標(biāo)準(zhǔn)接口,它允許兩個(gè)或多個(gè)應(yīng)用程序在相同機(jī)器上,或者是通過(guò)網(wǎng)絡(luò)相互交流。Winsock是真正的協(xié)議無(wú)關(guān)的接口,本章主要講述如何使用它來(lái)編寫應(yīng)用層的網(wǎng)絡(luò)應(yīng)用程序。2.1Winsock庫(kù)Winsock庫(kù)有兩個(gè)版本,Winsock1和Winsock2?,F(xiàn)在開(kāi)發(fā)網(wǎng)絡(luò)應(yīng)用程序都使用Winsock2,需要在程序中包含頭文件winsock2.h,它包含了絕大部分socket函數(shù)和相關(guān)結(jié)構(gòu)類型的聲明和定義。同時(shí)要添加的還有到WS2_32.lib庫(kù)的鏈接。包含必要的頭文件,設(shè)置好鏈接環(huán)境之后,便可進(jìn)行下面的編碼工作了。2.1Winsock庫(kù)Winsock庫(kù)的裝入和釋放每個(gè)Winsock應(yīng)用程序必須加載相應(yīng)版本的WinsockDLL。如果在調(diào)用Winsock函數(shù)前沒(méi)有加載Winsock庫(kù),函數(shù)返回SOCKET_ERROR,出錯(cuò)代碼將是WSANOTINITIALISED。加載Winsock庫(kù)的函數(shù)是WSAStartup,其定義如下。intWSAStartup(WORDwVersionRequested,//指定想要加載的Winsock庫(kù)的版本,高字節(jié)為次版本號(hào),低字節(jié)為主版本號(hào)LPWSADATAlpWSAData//一個(gè)指向WSADATA結(jié)構(gòu)的指針,用來(lái)返回DLL庫(kù)的詳細(xì)信息);wVersionRequested參數(shù)用來(lái)指定想要加載的Winsock庫(kù)的版本。為了建立此參數(shù)的值,可以使用宏MAKEWORD(x,y),其中x是高字節(jié),y是低字節(jié)。lpWSAData是一個(gè)指向LPWSADATA結(jié)構(gòu)的指針,WSAStartup使用所加載庫(kù)的版本信息填充它。typedefstructWSAData{WORDwVersion;//庫(kù)文件建議應(yīng)用程序使用的版本W(wǎng)ORDwHighVersion;//庫(kù)文件支持的最高版本charszDescription[WSADESCRIPTION_LEN+1];//庫(kù)描述字符串charszSystemStatus[WSASYS_STATUS_LEN+1];//系統(tǒng)狀態(tài)字符串unsignedshortiMaxSockets;//同時(shí)支持的最大套接字的數(shù)量unsignedshortiMaxUdpDg;//2.0版中已廢棄的參數(shù)charFAR*lpVendorInfo;//2.0版中已廢棄的參數(shù)}WSADATA,FAR*LPWSADATA;函數(shù)調(diào)用成功返回0。否則要調(diào)用WSAGetLastError函數(shù)查看出錯(cuò)的原因。此函數(shù)的作用相當(dāng)于API函數(shù)GetLastError,它取得最后發(fā)生錯(cuò)誤的代碼。每一個(gè)對(duì)WSAStartup的調(diào)用必須對(duì)應(yīng)一個(gè)對(duì)WSACleanup的調(diào)用,這個(gè)函數(shù)釋放Winsock庫(kù)。intWSACleanup(void);所有的Winsock函數(shù)都是從WS2_32.DLL導(dǎo)出的,VC++在默認(rèn)情況下并沒(méi)有鏈接到該庫(kù),如果想使用WinsockAPI,就必須包含相應(yīng)的庫(kù)文件。#pragmacomment(lib,"WS2_32")2.1.2封裝CInitSock類每次寫網(wǎng)絡(luò)程序都必須編寫代碼載入和釋放Winsock庫(kù),為了今后討論方便,這里封裝一個(gè)CInitSock類來(lái)管理Winsock庫(kù),類的使用方法見(jiàn)下一小節(jié)。#include<winsock2.h>//initsock.h文件#pragmacomment(lib,"WS2_32")//鏈接到WS2_32.libclassCInitSock{public:CInitSock(BYTEminorVer=2,BYTEmajorVer=2){//初始化WS2_32.dllWSADATAwsaData;WORDsockVersion=MAKEWORD(minorVer,majorVer);if(::WSAStartup(sockVersion,&wsaData)!=0){exit(0);}}~CInitSock(){::WSACleanup();}};2.2Winsock的尋址方式和字節(jié)順序因?yàn)閃insock要兼容多個(gè)協(xié)議,所以必須使用通用的尋址方式。TCP/IP使用IP地址和端口號(hào)來(lái)指定一個(gè)地址,但是其他協(xié)議也許采用不同的形式。如果Winsock強(qiáng)迫使用特定的尋址方式,添加其他協(xié)議就不大可能了。Winsock的第一個(gè)版本使用sockaddr結(jié)構(gòu)來(lái)解決此問(wèn)題。structsockaddr
{
u_shortsa_family;charsa_data[14];};2.2Winsock的尋址方式和字節(jié)順序在這個(gè)結(jié)構(gòu)中,第一個(gè)成員sa_family指定了這個(gè)地址使用的地址家族。sa_data成員存儲(chǔ)的數(shù)據(jù)在不同的地址家族中可能不同。本書僅僅使用Internet地址家族(TCP/IP),Winsock已經(jīng)定義了sockaddr結(jié)構(gòu)的TCP/IP版本——sockaddr_in結(jié)構(gòu)。它們本質(zhì)上是相同的結(jié)構(gòu),但是第2個(gè)更容易操作。在Winsock中,應(yīng)用程序通過(guò)SOCKADDR_IN結(jié)構(gòu)來(lái)指定IP地址和端口號(hào),定義如下。structsockaddr_in{shortsin_family;//地址家族(即指定地址格式),應(yīng)為AF_INETu_shortsin_port;//端口號(hào)structin_addrsin_addr;//IP地址charsin_zero[8];//空字節(jié),要設(shè)為0};(1)sin_family域必須設(shè)為AF_INET,它告訴Winsock程序使用的是IP地址家族。(2)sin_port域指定了TCP或UDP通信服務(wù)的端口號(hào)。應(yīng)用程序在選擇端口號(hào)時(shí)必須小心,因?yàn)橛幸恍┒丝谔?hào)是保留給公共服務(wù)使用的,如FTP和HTTP?;旧希丝谔?hào)可分成如下3個(gè)范圍:公共的、注冊(cè)的、動(dòng)態(tài)的(或私有的)。z0~1023由IANA(InternetAssignedNumbersAuthority)管理,保留為公共的服務(wù)使用。z1024~49151是普通用戶注冊(cè)的端口號(hào),由IANA列出。z49152~65535是動(dòng)態(tài)和/或私有的端口號(hào)。2.2Winsock的尋址方式和字節(jié)順序普通用戶應(yīng)用程序應(yīng)該選擇1024~49151之間的注冊(cè)了的端口號(hào),以避免使用了一個(gè)其他應(yīng)用程序或者系統(tǒng)服務(wù)已經(jīng)使用的端口號(hào)。在49152~65535之間的端口號(hào)也可以自由地使用,因?yàn)闆](méi)有服務(wù)注冊(cè)這些端口號(hào)。(3)sin_addr域用來(lái)存儲(chǔ)IP地址(32位),它被定義為一個(gè)聯(lián)合來(lái)處理整個(gè)32位的值,兩個(gè)16位部分或者每個(gè)字節(jié)單獨(dú)分開(kāi)。描述32位IP地址的in_addr結(jié)構(gòu)定義如下。structin_addr{union{struct{u_chars_b1,s_b2,s_b3,s_b4;}S_un_b;//以4個(gè)u_char來(lái)描述struct{u_shorts_w1,s_w2;}S_un_w;//以2個(gè)u_short來(lái)描述u_longS_addr;//以1個(gè)u_long來(lái)描述}S_un;};2.2Winsock的尋址方式和字節(jié)順序用字符串“aa.bb.cc.dd”表示IP地址時(shí),字符串中由點(diǎn)分開(kāi)的4個(gè)域是以字符串的形式對(duì)in_addr結(jié)構(gòu)中的4個(gè)u_char值的描述。由于每個(gè)字節(jié)的數(shù)值范圍是0~255,所以各域的值都不可超過(guò)255。(4)最后一個(gè)域sin_zero沒(méi)有使用,是為了與SOCKADDR結(jié)構(gòu)大小相同才設(shè)置的。應(yīng)用程序可以使用inet_addr函數(shù)將一個(gè)由小數(shù)點(diǎn)分隔的十進(jìn)制IP地址字符串轉(zhuǎn)化成由32位二進(jìn)制數(shù)表示的IP地址。inet_ntoa是inet_addr函數(shù)的逆函數(shù),它將一個(gè)網(wǎng)絡(luò)字節(jié)順序的32位IP地址轉(zhuǎn)化成字符串。unsignedlonginet_addr(constchar*cp);//將一個(gè)"aa.bb.cc.dd"類型的IP地址字符串轉(zhuǎn)化為32位的二進(jìn)制數(shù)char*inet_ntoa(structin_addrin);//將32位的二進(jìn)制數(shù)轉(zhuǎn)化為字符串注意,inet_addr返回的32位二進(jìn)制數(shù)是用網(wǎng)絡(luò)順序存儲(chǔ)的,下一小節(jié)詳細(xì)講述字節(jié)順序。2.2Winsock的尋址方式和字節(jié)順序2.2.2字節(jié)順序字節(jié)順序是長(zhǎng)度跨越多個(gè)字節(jié)的數(shù)據(jù)被存儲(chǔ)的順序。例如,一個(gè)32位的長(zhǎng)整型0x12345678跨越4個(gè)字節(jié)(每個(gè)字節(jié)8位)。Intelx86機(jī)器使用小尾順序(little-endian),意思是最不重要的字節(jié)首先存儲(chǔ)。因此,數(shù)據(jù)0x12345678在內(nèi)存中的存放順序是0x78、0x56、0x34、0x12。大多數(shù)不使用小尾順序的機(jī)器使用大尾順序(big-endian),即最重要的字節(jié)首先存儲(chǔ)。同樣的值在內(nèi)存中的存放順序?qū)⑹?x12、0x34、0x56、0x78。因?yàn)閰f(xié)議數(shù)據(jù)要在這些機(jī)器間傳輸,所以就必須選定其中的一種方式做為標(biāo)準(zhǔn),否則會(huì)引起混淆。TCP/IP統(tǒng)一規(guī)定使用大尾方式傳輸數(shù)據(jù),也稱為網(wǎng)絡(luò)字節(jié)順序。例如,端口號(hào)(它是一個(gè)16位的數(shù)字)12345(0x3039)的存儲(chǔ)順序是0x30、0x39。32位的IP地址也是以這種方式存儲(chǔ)的,IP地址的4部分存儲(chǔ)在4個(gè)字節(jié)中,第一部分存儲(chǔ)在第一個(gè)字節(jié)中。上述sockaddr和sockaddr_in結(jié)構(gòu)中,除了sin_family成員(它不是協(xié)議的一部分)外,其他所有值必須以網(wǎng)絡(luò)字節(jié)順序存儲(chǔ)。Winsock提供了一些函數(shù)來(lái)處理本地機(jī)器的字節(jié)順2.2Winsock的尋址方式和字節(jié)順序2.2.2字節(jié)順序u_shorthtons(u_shorthostshort);//將u_short類型變量從主機(jī)字節(jié)順序轉(zhuǎn)化到TCP/IP網(wǎng)絡(luò)字節(jié)順序u_longhtonl(u_longhostlong);//將u_long類型變量從主機(jī)字節(jié)順序轉(zhuǎn)化到TCP/IP網(wǎng)絡(luò)字節(jié)順序u_shortntohs(u_shortnetshort);//將u_short類型變量從TCP/IP網(wǎng)絡(luò)字節(jié)順序轉(zhuǎn)化到主機(jī)字節(jié)順序u_longntohl(u_longnetlong);//將u_long類型變量從TCP/IP網(wǎng)絡(luò)字節(jié)順序轉(zhuǎn)化到主機(jī)字節(jié)順序2.2Winsock的尋址方式和字節(jié)順序初始化sockaddr_in結(jié)構(gòu)sockaddr_insockAddr;//設(shè)置地址家族sockAddr.sin_family=AF_INET;//轉(zhuǎn)化端口號(hào)6789到網(wǎng)絡(luò)字節(jié)順序,并安排它到正確的成員sockAddr.sin_port=htons(6789);//inet_addr函數(shù)轉(zhuǎn)化一個(gè)"aa.bb.cc.dd"類型的IP地址字符串到長(zhǎng)整型,//它是以網(wǎng)絡(luò)字節(jié)順序記錄的IP地址sockAddr.sin_addr.S_un.S_addr=inet_addr("");//也可以用下面的代碼設(shè)置IP地址(通過(guò)設(shè)置4個(gè)字節(jié)部分,設(shè)置sockAddr的地址)/*sockAddr.sin_addr.S_un.S_un_b.s_b1=127;sockAddr.sin_addr.S_un.S_un_b.s_b2=0;sockAddr.sin_addr.S_un.S_un_b.s_b3=0;sockAddr.sin_addr.S_un.S_un_b.s_b4=1;*/2.2Winsock的尋址方式和字節(jié)順序2.2.3獲取地址信息通常,主機(jī)上的接口被靜態(tài)地指定一個(gè)IP地址,或者是由配置協(xié)議來(lái)分配,如動(dòng)態(tài)主機(jī)配置協(xié)議(DHCP)。如果DHCP服務(wù)器不能到達(dá),系統(tǒng)會(huì)使用AutomaticPrivateIPAddressing(APIPA)自動(dòng)分配/16范圍內(nèi)的地址。2.2Winsock的尋址方式和字節(jié)順序2.2.3獲取地址信息1.獲取本機(jī)IP地址獲取本機(jī)的IP地址比較簡(jiǎn)單,下面的GetAllIps例子打印出了本機(jī)使用的所有IP(一個(gè)適配器一個(gè)IP地址),程序代碼如下。#include"../common/InitSock.h"http://GetAllIps工程#include<stdio.h>CInitSockinitSock;//初始化Winsock庫(kù)voidmain(){charszHost[256];
//取得本地主機(jī)名稱
::gethostname(szHost,256);
//通過(guò)主機(jī)名得到地址信息
hostent*pHost=::gethostbyname(szHost);
//打印出所有IP地址
in_addraddr;
for(inti=0;;i++)
{char*p=pHost->h_addr_list[i];//p指向一個(gè)32位的IP地址
if(p==NULL)break;
memcpy(&addr.S_un.S_addr,p,pHost->h_length);
char*szIp=::inet_ntoa(addr);
printf("本機(jī)IP地址:%s\n",szIp);}}GetAllIps先調(diào)用gethostname取得本地主機(jī)的名稱,然后通過(guò)主機(jī)名得到其地址信息。2.2Winsock的尋址方式和字節(jié)順序2.2.3獲取地址信息有時(shí)為了檢測(cè)網(wǎng)絡(luò),或者為了一些其他特殊的目的,需要自己來(lái)直接操作原始數(shù)據(jù)幀(第9章再具體講述),這就需要獲取自己和LAN中其他主機(jī)的MAC地址。獲取本地機(jī)器的MAC地址很容易,使用幫助函數(shù)GetAdaptersInfo即可。此函數(shù)的作用是獲取本地機(jī)器的適配器信息,用法如下。DWORDGetAdaptersInfo(PIP_ADAPTER_INFOpAdapterInfo,//指向一個(gè)緩沖區(qū),用來(lái)取得IP_ADAPTER_INFO結(jié)構(gòu)的列表–PULONGpOutBufLen//用來(lái)指定上面緩沖區(qū)的大小。如果大小不夠,此參數(shù)返回所需大小);//函數(shù)調(diào)用成功返回ERROR_SUCCESSIP_ADAPTER_INFO結(jié)構(gòu)包含了本地計(jì)算機(jī)上網(wǎng)絡(luò)適配器的信息,定義如下。typedefstruct_IP_ADAPTER_INFO{struct_IP_ADAPTER_INFO*Next;//指向適配器列表中的下一個(gè)適配器(計(jì)算機(jī)可能有多個(gè)適配器)2.2Winsock的尋址方式和字節(jié)順序2.2.3獲取地址信息程序見(jiàn)LocalhostInfo2.3Winsock編程詳解使用TCP創(chuàng)建網(wǎng)絡(luò)應(yīng)用程序稍微復(fù)雜一些,因?yàn)門CP是面向連接的協(xié)議,需要通信雙方首先建立一個(gè)連接。本節(jié)先以建立簡(jiǎn)單的TCP客戶端和服務(wù)器端應(yīng)用程序?yàn)槔?,詳?xì)說(shuō)明Winsock的編程流程,然后再介紹較為簡(jiǎn)單的UDP編程。2.3Winsock編程詳解2.3.1Winsock編程流程1.套接字的創(chuàng)建和關(guān)閉使用套接字之前,必須調(diào)用socket函數(shù)創(chuàng)建一個(gè)套接字對(duì)象,此函數(shù)調(diào)用成功將返回套接字句柄。SOCKETsocket(intaf,//用來(lái)指定套接示使用的地址格式,WinSock中只支持AF_INETinttype,//用來(lái)指定套接字的類型intprotocol//配合type參數(shù)使用,用來(lái)指定使用的協(xié)議類型??梢允荌PPROTO_TCP等);2.3Winsock編程詳解2.3.1Winsock編程流程1.套接字的創(chuàng)建和關(guān)閉當(dāng)type參數(shù)指定為SOCK_STREAM和SOCK_DGRAM時(shí),系統(tǒng)已經(jīng)明確使用TCP和UDP來(lái)工作,所以protocol參數(shù)可以指定為0。函數(shù)執(zhí)行失敗返回INVALID_SOCKET(即-1),可以通過(guò)調(diào)用WSAGetLastError取得錯(cuò)誤代碼。也可以使用Winsock2的新函數(shù)WSASocket來(lái)創(chuàng)建套接字,與socket相比,它提供了更多的參數(shù),如可以自己選擇下層服務(wù)提供者、設(shè)置重疊標(biāo)志等,后面再具體討論它。當(dāng)不使用socket創(chuàng)建的套接字時(shí),應(yīng)該調(diào)用closesocket函數(shù)將它關(guān)閉。如果沒(méi)有錯(cuò)誤發(fā)生,函數(shù)返回0,否則返回SOCKET_ERROR。函數(shù)用法如下。intclosesocket(SOCKETs);//函數(shù)惟一的參數(shù)就是要關(guān)閉的套接字的句柄2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號(hào)bind函數(shù)用在沒(méi)有建立連接的套接字上,它的作用是綁定面向連接的或者無(wú)連接的套接字。套接字被socket函數(shù)創(chuàng)建以后,存在于指定的地址家族里,但它是未命名的。bind函數(shù)通過(guò)安排一個(gè)本地名稱到未命名的socket而建立此socket的本地關(guān)聯(lián)。本地名稱包含3部分:主機(jī)地址、協(xié)議號(hào)(分別為UDP或TCP)和端口號(hào)。本節(jié)的TCPServer程序使用以下代碼綁定套接字s到本地地址。2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號(hào)//填充sockaddr_in結(jié)構(gòu)sockaddr_insin;sin.sin_family=AF_INET;sin.sin_port=htons(4567);sin.sin_addr.S_un.S_addr=INADDR_ANY;//綁定這個(gè)套接字到一個(gè)本地地址if(::bind(sListen,(LPSOCKADDR)&sin,sizeof(sin))==SOCKET_ERROR){printf("Failedbind()\n");return0;}sockaddr_in結(jié)構(gòu)中的sin_familly字段用來(lái)指定地址家族,該字段和socket函數(shù)中的af參數(shù)的含義相同,所以惟一可以使用的值就是AF_INET。sin_port字段和sin_addr字段分別指定套接字需要綁定的端口號(hào)和IP地址。放入這兩個(gè)字段的數(shù)據(jù)的字節(jié)順序必須是網(wǎng)絡(luò)字節(jié)順序。因?yàn)榫W(wǎng)絡(luò)字節(jié)順序和IntelCPU的字節(jié)順序剛好相反,所以必須首先使用htons函數(shù)進(jìn)行轉(zhuǎn)換。如果應(yīng)用程序不關(guān)心所使用的地址,可以指定Internet地址為INADDR_ANY,指定端口號(hào)為0。如果Internet地址等于INADDR_ANY,系統(tǒng)會(huì)自動(dòng)使用當(dāng)前主機(jī)配置的所有IP地址,簡(jiǎn)化了程序設(shè)計(jì);如果端口號(hào)等于0,程序執(zhí)行時(shí)系統(tǒng)會(huì)為這個(gè)應(yīng)用程序分配惟一的端口號(hào),其值在1024~5000之間。應(yīng)用程序可以在bind之后使用getsockname來(lái)知道為它分配的地址。但是要注意,直到套接字連接上之后getsockname才可能填寫Internet地址,因?yàn)閷?duì)一個(gè)主機(jī)來(lái)說(shuō)可能有多個(gè)地址是可用的。TCP客戶端程序也可以在不顯式綁定地址和端口號(hào)的情況下發(fā)送數(shù)據(jù)或者連接。在這種情況下,系統(tǒng)也會(huì)默認(rèn)地為套接字綁定一個(gè)本地端口(1024~5000之間)。2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號(hào)3.設(shè)置套接字進(jìn)入監(jiān)聽(tīng)狀態(tài)listen函數(shù)設(shè)置套接字進(jìn)入監(jiān)聽(tīng)狀態(tài)。intlisten(SOCKETs,//套接字句柄intbacklog//監(jiān)聽(tīng)隊(duì)列中允許保持的尚未處理的最大連接數(shù)量);為了接受連接,首先使用socket函數(shù)創(chuàng)建套接字,然后使用bind函數(shù)將它綁定到本地地址,再用listen函數(shù)為到達(dá)的連接指定backlog,最后使用accept接受請(qǐng)求的連接。listen僅應(yīng)用在支持連接的套接字上,如SOCK_STREAM類型的套接字。函數(shù)執(zhí)行成功后,套接字s進(jìn)入了被動(dòng)模式,到來(lái)的連接會(huì)被通知要排隊(duì)等候接受處理。在同一時(shí)間處理多個(gè)連接請(qǐng)求的服務(wù)器通常使用listen函數(shù),如果一個(gè)連接請(qǐng)求到達(dá),并且排隊(duì)已滿,客戶端將接收到WSAECONNREFUSED錯(cuò)誤。2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號(hào)3.設(shè)置套接字進(jìn)入監(jiān)聽(tīng)狀態(tài)4.接受連接請(qǐng)求accept函數(shù)用于接受到來(lái)的連接。SOCKETaccept(SOCKETs,//套接字句柄structsockaddr*addr,//一個(gè)指向sockaddr_in結(jié)構(gòu)的指針,用于取得對(duì)方的地址信息int*addrlen//一個(gè)指向地址長(zhǎng)度的指針);2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號(hào)3.設(shè)置套接字進(jìn)入監(jiān)聽(tīng)狀態(tài)4.接受連接請(qǐng)求該函數(shù)在s上取出未處理連接中的第一個(gè)連接,然后為這個(gè)連接創(chuàng)建新的套接字,返回它的句柄。新創(chuàng)建的套接字是處理實(shí)際連接的套接字,它與s有相同的屬性。程序默認(rèn)工作在阻塞模式下,這種方式下如果沒(méi)有未處理的連接存在,accept函數(shù)會(huì)一直等待下去,直到有新的連接發(fā)生才返回。addrlen參數(shù)用于指定addr所指空間的大小,也用于返回地址的實(shí)際長(zhǎng)度。如果addr或者addrlen是NULL,則沒(méi)有關(guān)于遠(yuǎn)程地址的信息返回??蛻舳顺绦蛟趧?chuàng)建套接字之后,要使用connect函數(shù)請(qǐng)求與服務(wù)器連接,2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號(hào)3.設(shè)置套接字進(jìn)入監(jiān)聽(tīng)狀態(tài)4.接受連接請(qǐng)求5.收發(fā)數(shù)據(jù)對(duì)流套接字來(lái)說(shuō),一般使用send和recv函數(shù)來(lái)收發(fā)數(shù)據(jù)。intsend(SOCKETs,//套接字句柄constcharFAR*buf,//要發(fā)送數(shù)據(jù)的緩沖區(qū)地址intlen,//緩沖區(qū)長(zhǎng)度intflags//指定了調(diào)用方式,通常設(shè)位0);intrecv(SOCKETs,charFAR*buf,intlen,int);send函數(shù)在一個(gè)連接的套接字上發(fā)送緩沖區(qū)內(nèi)的數(shù)據(jù),返回發(fā)送數(shù)據(jù)的實(shí)際字節(jié)數(shù)。recv函數(shù)從對(duì)方接收數(shù)據(jù),并將其存儲(chǔ)到指定的緩沖區(qū)。flags參數(shù)在這兩函數(shù)中通常設(shè)為0。在阻塞模式下,send將會(huì)阻塞線程的執(zhí)行直到所有的數(shù)據(jù)發(fā)送完畢(或者發(fā)生錯(cuò)誤),而recv函數(shù)將返回盡可能多的當(dāng)前可用信息,直到達(dá)到緩沖區(qū)指定的大小。2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號(hào)2.3.2典型過(guò)程圖TCP服務(wù)器程序和客戶程序的創(chuàng)建過(guò)程如圖2.2所示。服務(wù)器端創(chuàng)建監(jiān)聽(tīng)套接字,并為它關(guān)聯(lián)一個(gè)本地地址(指定IP地址和端口號(hào)),然后進(jìn)入監(jiān)聽(tīng)狀態(tài)準(zhǔn)備接受客戶的連接請(qǐng)求。為了接受客戶端的連接請(qǐng)求,服務(wù)器端必須調(diào)用accept函數(shù)??蛻舳藙?chuàng)建套接字后即可調(diào)用connect函數(shù)去試圖連接服務(wù)器監(jiān)聽(tīng)套接字。當(dāng)服務(wù)器端的accept函數(shù)返回后,connect函數(shù)也返回。此時(shí)客戶端使用socket函數(shù)創(chuàng)建的套接字,服務(wù)器端使用accept函數(shù)創(chuàng)建的套接字,雙方就可以通信了。2.3Winsock編程詳解2.3Winsock編程詳解2.3.3TCP服務(wù)器和客戶端程序舉例下面是最簡(jiǎn)單的TCP服務(wù)器程序和TCP客戶端程序的例子。這兩個(gè)程序都是控制臺(tái)界面的Win32應(yīng)用程序,分別在配套光盤的TCPServer和TCPClient工程下。運(yùn)行服務(wù)器程序TCPServer,如果沒(méi)有錯(cuò)誤發(fā)生,將在本地機(jī)器上的4567端口上等待客戶端的連接。如果沒(méi)有連接請(qǐng)求,服務(wù)器會(huì)一直處于休眠狀態(tài)。運(yùn)行服務(wù)器之后,再運(yùn)行客戶端程序TCPClient,其最終效果如圖2.3所示。客戶端連接到了服務(wù)器,雙方套接字可以通信了。程序見(jiàn)TCPServer2.3Winsock編程詳解2.3.4UDP編程TCP由于可靠、穩(wěn)定的特點(diǎn)而被用在大部分場(chǎng)合,但它對(duì)系統(tǒng)資源要求比較高。UDP是一個(gè)簡(jiǎn)單的面向數(shù)據(jù)報(bào)的傳輸層協(xié)議,又叫用戶數(shù)據(jù)報(bào)協(xié)議。它提供了無(wú)連接的、不可靠的數(shù)據(jù)傳輸服務(wù)。無(wú)連接是指它不像TCP那樣在通信前先與對(duì)方建立連接以確定對(duì)方的狀態(tài)。不可靠是指它直接按照指定IP地址和端口號(hào)將數(shù)據(jù)包發(fā)出去,如果對(duì)方不在線的話數(shù)據(jù)就可能丟失。1.UDP編程流程(1)服務(wù)器端程序設(shè)計(jì)流程如下。①創(chuàng)建套接字(socket)。②綁定IP地址和端口(bind)。③收發(fā)數(shù)據(jù)(sendto/recvfrom)。④關(guān)閉連接(closesocket)。(2)客戶端程序設(shè)計(jì)流程如下。①創(chuàng)建套接字(socket)。②收發(fā)數(shù)據(jù)(sendto/recvfrom)。③關(guān)閉連接(closesocket)。UDP用于發(fā)送和接收數(shù)據(jù)的函數(shù)是sendto和recvfrom,它們的用法如下。同樣,UDP接收數(shù)據(jù)時(shí)也需要知道通信對(duì)端的地址信息。intrecvfrom(SOCKETs,charFAR*buf,intlen,intflags,structsockaddrFAR*from,intFAR*fromlen);這個(gè)函數(shù)比recv函數(shù)多出
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 工地推車考試題及答案大全
- 高中模似考試題及答案
- 項(xiàng)目團(tuán)隊(duì)溝通與協(xié)作任務(wù)分配表
- 產(chǎn)品測(cè)試與驗(yàn)證流程及標(biāo)準(zhǔn)化文檔
- 高考發(fā)酵工程考試題及答案
- 高級(jí)會(huì)考試題及答案
- 2025年小考語(yǔ)文期末真題及答案
- 甘肅英語(yǔ)聯(lián)考試題及答案
- 2025年巴盟教師考試題目及答案
- 產(chǎn)品功能用戶測(cè)試標(biāo)準(zhǔn)與步驟指南
- 食品有限公司化學(xué)品管理程序
- MOOC 頸肩腰腿痛中醫(yī)防治-暨南大學(xué) 中國(guó)大學(xué)慕課答案
- 2024年米粉項(xiàng)目實(shí)施方案
- 日本商務(wù)談判風(fēng)格剖析課件
- 《智能交通概論》 課件 陳嵐 任務(wù)3、4 輔助出行的出行者信息系統(tǒng)、智能化的公共交通系統(tǒng)
- 頂管頂力計(jì)算
- 綜合實(shí)踐活動(dòng)課程的設(shè)計(jì)與實(shí)施
- 機(jī)械制圖習(xí)題集(第五版)習(xí)題解答
- 《影視鑒賞》教學(xué)課件 《影視鑒賞》第三章
- 市政工程監(jiān)理平行檢驗(yàn)表(套)
- 四議兩公開(kāi)工作法課件
評(píng)論
0/150
提交評(píng)論