版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第二章Winsock編程接口Winsock是Windows下網(wǎng)絡(luò)編程的標(biāo)準(zhǔn)接口,它允許兩個或多個應(yīng)用程序在相同機(jī)器上,或者是通過網(wǎng)絡(luò)相互交流。Winsock是真正的協(xié)議無關(guān)的接口,本章主要講述如何使用它來編寫應(yīng)用層的網(wǎng)絡(luò)應(yīng)用程序。2.1Winsock庫Winsock庫有兩個版本,Winsock1和Winsock2。現(xiàn)在開發(fā)網(wǎng)絡(luò)應(yīng)用程序都使用Winsock2,需要在程序中包含頭文件winsock2.h,它包含了絕大部分socket函數(shù)和相關(guān)結(jié)構(gòu)類型的聲明和定義。同時(shí)要添加的還有到WS2_32.lib庫的鏈接。包含必要的頭文件,設(shè)置好鏈接環(huán)境之后,便可進(jìn)行下面的編碼工作了。2.1Winsock庫Winsock庫的裝入和釋放每個Winsock應(yīng)用程序必須加載相應(yīng)版本的WinsockDLL。如果在調(diào)用Winsock函數(shù)前沒有加載Winsock庫,函數(shù)返回SOCKET_ERROR,出錯代碼將是WSANOTINITIALISED。加載Winsock庫的函數(shù)是WSAStartup,其定義如下。intWSAStartup(WORDwVersionRequested,//指定想要加載的Winsock庫的版本,高字節(jié)為次版本號,低字節(jié)為主版本號LPWSADATAlpWSAData//一個指向WSADATA結(jié)構(gòu)的指針,用來返回DLL庫的詳細(xì)信息);wVersionRequested參數(shù)用來指定想要加載的Winsock庫的版本。為了建立此參數(shù)的值,可以使用宏MAKEWORD(x,y),其中x是高字節(jié),y是低字節(jié)。lpWSAData是一個指向LPWSADATA結(jié)構(gòu)的指針,WSAStartup使用所加載庫的版本信息填充它。typedefstructWSAData{WORDwVersion;//庫文件建議應(yīng)用程序使用的版本W(wǎng)ORDwHighVersion;//庫文件支持的最高版本charszDescription[WSADESCRIPTION_LEN+1];//庫描述字符串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ù)查看出錯的原因。此函數(shù)的作用相當(dāng)于API函數(shù)GetLastError,它取得最后發(fā)生錯誤的代碼。每一個對WSAStartup的調(diào)用必須對應(yīng)一個對WSACleanup的調(diào)用,這個函數(shù)釋放Winsock庫。intWSACleanup(void);所有的Winsock函數(shù)都是從WS2_32.DLL導(dǎo)出的,VC++在默認(rèn)情況下并沒有鏈接到該庫,如果想使用WinsockAPI,就必須包含相應(yīng)的庫文件。#pragmacomment(lib,"WS2_32")2.1.2封裝CInitSock類每次寫網(wǎng)絡(luò)程序都必須編寫代碼載入和釋放Winsock庫,為了今后討論方便,這里封裝一個CInitSock類來管理Winsock庫,類的使用方法見下一小節(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要兼容多個協(xié)議,所以必須使用通用的尋址方式。TCP/IP使用IP地址和端口號來指定一個地址,但是其他協(xié)議也許采用不同的形式。如果Winsock強(qiáng)迫使用特定的尋址方式,添加其他協(xié)議就不大可能了。Winsock的第一個版本使用sockaddr結(jié)構(gòu)來解決此問題。structsockaddr
{
u_shortsa_family;charsa_data[14];};2.2Winsock的尋址方式和字節(jié)順序在這個結(jié)構(gòu)中,第一個成員sa_family指定了這個地址使用的地址家族。sa_data成員存儲的數(shù)據(jù)在不同的地址家族中可能不同。本書僅僅使用Internet地址家族(TCP/IP),Winsock已經(jīng)定義了sockaddr結(jié)構(gòu)的TCP/IP版本——sockaddr_in結(jié)構(gòu)。它們本質(zhì)上是相同的結(jié)構(gòu),但是第2個更容易操作。在Winsock中,應(yīng)用程序通過SOCKADDR_IN結(jié)構(gòu)來指定IP地址和端口號,定義如下。structsockaddr_in{shortsin_family;//地址家族(即指定地址格式),應(yīng)為AF_INETu_shortsin_port;//端口號structin_addrsin_addr;//IP地址charsin_zero[8];//空字節(jié),要設(shè)為0};(1)sin_family域必須設(shè)為AF_INET,它告訴Winsock程序使用的是IP地址家族。(2)sin_port域指定了TCP或UDP通信服務(wù)的端口號。應(yīng)用程序在選擇端口號時(shí)必須小心,因?yàn)橛幸恍┒丝谔柺潜A艚o公共服務(wù)使用的,如FTP和HTTP?;旧?,端口號可分成如下3個范圍:公共的、注冊的、動態(tài)的(或私有的)。z0~1023由IANA(InternetAssignedNumbersAuthority)管理,保留為公共的服務(wù)使用。z1024~49151是普通用戶注冊的端口號,由IANA列出。z49152~65535是動態(tài)和/或私有的端口號。2.2Winsock的尋址方式和字節(jié)順序普通用戶應(yīng)用程序應(yīng)該選擇1024~49151之間的注冊了的端口號,以避免使用了一個其他應(yīng)用程序或者系統(tǒng)服務(wù)已經(jīng)使用的端口號。在49152~65535之間的端口號也可以自由地使用,因?yàn)闆]有服務(wù)注冊這些端口號。(3)sin_addr域用來存儲IP地址(32位),它被定義為一個聯(lián)合來處理整個32位的值,兩個16位部分或者每個字節(jié)單獨(dú)分開。描述32位IP地址的in_addr結(jié)構(gòu)定義如下。structin_addr{union{struct{u_chars_b1,s_b2,s_b3,s_b4;}S_un_b;//以4個u_char來描述struct{u_shorts_w1,s_w2;}S_un_w;//以2個u_short來描述u_longS_addr;//以1個u_long來描述}S_un;};2.2Winsock的尋址方式和字節(jié)順序用字符串“aa.bb.cc.dd”表示IP地址時(shí),字符串中由點(diǎn)分開的4個域是以字符串的形式對in_addr結(jié)構(gòu)中的4個u_char值的描述。由于每個字節(jié)的數(shù)值范圍是0~255,所以各域的值都不可超過255。(4)最后一個域sin_zero沒有使用,是為了與SOCKADDR結(jié)構(gòu)大小相同才設(shè)置的。應(yīng)用程序可以使用inet_addr函數(shù)將一個由小數(shù)點(diǎn)分隔的十進(jìn)制IP地址字符串轉(zhuǎn)化成由32位二進(jìn)制數(shù)表示的IP地址。inet_ntoa是inet_addr函數(shù)的逆函數(shù),它將一個網(wǎng)絡(luò)字節(jié)順序的32位IP地址轉(zhuǎn)化成字符串。unsignedlonginet_addr(constchar*cp);//將一個"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ò)順序存儲的,下一小節(jié)詳細(xì)講述字節(jié)順序。2.2Winsock的尋址方式和字節(jié)順序2.2.2字節(jié)順序字節(jié)順序是長度跨越多個字節(jié)的數(shù)據(jù)被存儲的順序。例如,一個32位的長整型0x12345678跨越4個字節(jié)(每個字節(jié)8位)。Intelx86機(jī)器使用小尾順序(little-endian),意思是最不重要的字節(jié)首先存儲。因此,數(shù)據(jù)0x12345678在內(nèi)存中的存放順序是0x78、0x56、0x34、0x12。大多數(shù)不使用小尾順序的機(jī)器使用大尾順序(big-endian),即最重要的字節(jié)首先存儲。同樣的值在內(nèi)存中的存放順序?qū)⑹?x12、0x34、0x56、0x78。因?yàn)閰f(xié)議數(shù)據(jù)要在這些機(jī)器間傳輸,所以就必須選定其中的一種方式做為標(biāo)準(zhǔn),否則會引起混淆。TCP/IP統(tǒng)一規(guī)定使用大尾方式傳輸數(shù)據(jù),也稱為網(wǎng)絡(luò)字節(jié)順序。例如,端口號(它是一個16位的數(shù)字)12345(0x3039)的存儲順序是0x30、0x39。32位的IP地址也是以這種方式存儲的,IP地址的4部分存儲在4個字節(jié)中,第一部分存儲在第一個字節(jié)中。上述sockaddr和sockaddr_in結(jié)構(gòu)中,除了sin_family成員(它不是協(xié)議的一部分)外,其他所有值必須以網(wǎng)絡(luò)字節(jié)順序存儲。Winsock提供了一些函數(shù)來處理本地機(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)化端口號6789到網(wǎng)絡(luò)字節(jié)順序,并安排它到正確的成員sockAddr.sin_port=htons(6789);//inet_addr函數(shù)轉(zhuǎn)化一個"aa.bb.cc.dd"類型的IP地址字符串到長整型,//它是以網(wǎng)絡(luò)字節(jié)順序記錄的IP地址sockAddr.sin_addr.S_un.S_addr=inet_addr("");//也可以用下面的代碼設(shè)置IP地址(通過設(shè)置4個字節(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)地指定一個IP地址,或者是由配置協(xié)議來分配,如動態(tài)主機(jī)配置協(xié)議(DHCP)。如果DHCP服務(wù)器不能到達(dá),系統(tǒng)會使用AutomaticPrivateIPAddressing(APIPA)自動分配/16范圍內(nèi)的地址。2.2Winsock的尋址方式和字節(jié)順序2.2.3獲取地址信息1.獲取本機(jī)IP地址獲取本機(jī)的IP地址比較簡單,下面的GetAllIps例子打印出了本機(jī)使用的所有IP(一個適配器一個IP地址),程序代碼如下。#include"../common/InitSock.h"http://GetAllIps工程#include<stdio.h>CInitSockinitSock;//初始化Winsock庫voidmain(){charszHost[256];
//取得本地主機(jī)名稱
::gethostname(szHost,256);
//通過主機(jī)名得到地址信息
hostent*pHost=::gethostbyname(szHost);
//打印出所有IP地址
in_addraddr;
for(inti=0;;i++)
{char*p=pHost->h_addr_list[i];//p指向一個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ī)的名稱,然后通過主機(jī)名得到其地址信息。2.2Winsock的尋址方式和字節(jié)順序2.2.3獲取地址信息有時(shí)為了檢測網(wǎng)絡(luò),或者為了一些其他特殊的目的,需要自己來直接操作原始數(shù)據(jù)幀(第9章再具體講述),這就需要獲取自己和LAN中其他主機(jī)的MAC地址。獲取本地機(jī)器的MAC地址很容易,使用幫助函數(shù)GetAdaptersInfo即可。此函數(shù)的作用是獲取本地機(jī)器的適配器信息,用法如下。DWORDGetAdaptersInfo(PIP_ADAPTER_INFOpAdapterInfo,//指向一個緩沖區(qū),用來取得IP_ADAPTER_INFO結(jié)構(gòu)的列表–PULONGpOutBufLen//用來指定上面緩沖區(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;//指向適配器列表中的下一個適配器(計(jì)算機(jī)可能有多個適配器)2.2Winsock的尋址方式和字節(jié)順序2.2.3獲取地址信息程序見LocalhostInfo2.3Winsock編程詳解使用TCP創(chuàng)建網(wǎng)絡(luò)應(yīng)用程序稍微復(fù)雜一些,因?yàn)門CP是面向連接的協(xié)議,需要通信雙方首先建立一個連接。本節(jié)先以建立簡單的TCP客戶端和服務(wù)器端應(yīng)用程序?yàn)槔?,詳?xì)說明Winsock的編程流程,然后再介紹較為簡單的UDP編程。2.3Winsock編程詳解2.3.1Winsock編程流程1.套接字的創(chuàng)建和關(guān)閉使用套接字之前,必須調(diào)用socket函數(shù)創(chuàng)建一個套接字對象,此函數(shù)調(diào)用成功將返回套接字句柄。SOCKETsocket(intaf,//用來指定套接示使用的地址格式,WinSock中只支持AF_INETinttype,//用來指定套接字的類型intprotocol//配合type參數(shù)使用,用來指定使用的協(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來工作,所以protocol參數(shù)可以指定為0。函數(shù)執(zhí)行失敗返回INVALID_SOCKET(即-1),可以通過調(diào)用WSAGetLastError取得錯誤代碼。也可以使用Winsock2的新函數(shù)WSASocket來創(chuàng)建套接字,與socket相比,它提供了更多的參數(shù),如可以自己選擇下層服務(wù)提供者、設(shè)置重疊標(biāo)志等,后面再具體討論它。當(dāng)不使用socket創(chuàng)建的套接字時(shí),應(yīng)該調(diào)用closesocket函數(shù)將它關(guān)閉。如果沒有錯誤發(fā)生,函數(shù)返回0,否則返回SOCKET_ERROR。函數(shù)用法如下。intclosesocket(SOCKETs);//函數(shù)惟一的參數(shù)就是要關(guān)閉的套接字的句柄2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號bind函數(shù)用在沒有建立連接的套接字上,它的作用是綁定面向連接的或者無連接的套接字。套接字被socket函數(shù)創(chuàng)建以后,存在于指定的地址家族里,但它是未命名的。bind函數(shù)通過安排一個本地名稱到未命名的socket而建立此socket的本地關(guān)聯(lián)。本地名稱包含3部分:主機(jī)地址、協(xié)議號(分別為UDP或TCP)和端口號。本節(jié)的TCPServer程序使用以下代碼綁定套接字s到本地地址。2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號//填充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;//綁定這個套接字到一個本地地址if(::bind(sListen,(LPSOCKADDR)&sin,sizeof(sin))==SOCKET_ERROR){printf("Failedbind()\n");return0;}sockaddr_in結(jié)構(gòu)中的sin_familly字段用來指定地址家族,該字段和socket函數(shù)中的af參數(shù)的含義相同,所以惟一可以使用的值就是AF_INET。sin_port字段和sin_addr字段分別指定套接字需要綁定的端口號和IP地址。放入這兩個字段的數(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,指定端口號為0。如果Internet地址等于INADDR_ANY,系統(tǒng)會自動使用當(dāng)前主機(jī)配置的所有IP地址,簡化了程序設(shè)計(jì);如果端口號等于0,程序執(zhí)行時(shí)系統(tǒng)會為這個應(yīng)用程序分配惟一的端口號,其值在1024~5000之間。應(yīng)用程序可以在bind之后使用getsockname來知道為它分配的地址。但是要注意,直到套接字連接上之后getsockname才可能填寫Internet地址,因?yàn)閷σ粋€主機(jī)來說可能有多個地址是可用的。TCP客戶端程序也可以在不顯式綁定地址和端口號的情況下發(fā)送數(shù)據(jù)或者連接。在這種情況下,系統(tǒng)也會默認(rèn)地為套接字綁定一個本地端口(1024~5000之間)。2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號3.設(shè)置套接字進(jìn)入監(jiān)聽狀態(tài)listen函數(shù)設(shè)置套接字進(jìn)入監(jiān)聽狀態(tài)。intlisten(SOCKETs,//套接字句柄intbacklog//監(jiān)聽隊(duì)列中允許保持的尚未處理的最大連接數(shù)量);為了接受連接,首先使用socket函數(shù)創(chuàng)建套接字,然后使用bind函數(shù)將它綁定到本地地址,再用listen函數(shù)為到達(dá)的連接指定backlog,最后使用accept接受請求的連接。listen僅應(yīng)用在支持連接的套接字上,如SOCK_STREAM類型的套接字。函數(shù)執(zhí)行成功后,套接字s進(jìn)入了被動模式,到來的連接會被通知要排隊(duì)等候接受處理。在同一時(shí)間處理多個連接請求的服務(wù)器通常使用listen函數(shù),如果一個連接請求到達(dá),并且排隊(duì)已滿,客戶端將接收到WSAECONNREFUSED錯誤。2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號3.設(shè)置套接字進(jìn)入監(jiān)聽狀態(tài)4.接受連接請求accept函數(shù)用于接受到來的連接。SOCKETaccept(SOCKETs,//套接字句柄structsockaddr*addr,//一個指向sockaddr_in結(jié)構(gòu)的指針,用于取得對方的地址信息int*addrlen//一個指向地址長度的指針);2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號3.設(shè)置套接字進(jìn)入監(jiān)聽狀態(tài)4.接受連接請求該函數(shù)在s上取出未處理連接中的第一個連接,然后為這個連接創(chuàng)建新的套接字,返回它的句柄。新創(chuàng)建的套接字是處理實(shí)際連接的套接字,它與s有相同的屬性。程序默認(rèn)工作在阻塞模式下,這種方式下如果沒有未處理的連接存在,accept函數(shù)會一直等待下去,直到有新的連接發(fā)生才返回。addrlen參數(shù)用于指定addr所指空間的大小,也用于返回地址的實(shí)際長度。如果addr或者addrlen是NULL,則沒有關(guān)于遠(yuǎn)程地址的信息返回。客戶端程序在創(chuàng)建套接字之后,要使用connect函數(shù)請求與服務(wù)器連接,2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號3.設(shè)置套接字進(jìn)入監(jiān)聽狀態(tài)4.接受連接請求5.收發(fā)數(shù)據(jù)對流套接字來說,一般使用send和recv函數(shù)來收發(fā)數(shù)據(jù)。intsend(SOCKETs,//套接字句柄constcharFAR*buf,//要發(fā)送數(shù)據(jù)的緩沖區(qū)地址intlen,//緩沖區(qū)長度intflags//指定了調(diào)用方式,通常設(shè)位0);intrecv(SOCKETs,charFAR*buf,intlen,int);send函數(shù)在一個連接的套接字上發(fā)送緩沖區(qū)內(nèi)的數(shù)據(jù),返回發(fā)送數(shù)據(jù)的實(shí)際字節(jié)數(shù)。recv函數(shù)從對方接收數(shù)據(jù),并將其存儲到指定的緩沖區(qū)。flags參數(shù)在這兩函數(shù)中通常設(shè)為0。在阻塞模式下,send將會阻塞線程的執(zhí)行直到所有的數(shù)據(jù)發(fā)送完畢(或者發(fā)生錯誤),而recv函數(shù)將返回盡可能多的當(dāng)前可用信息,直到達(dá)到緩沖區(qū)指定的大小。2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號2.3.2典型過程圖TCP服務(wù)器程序和客戶程序的創(chuàng)建過程如圖2.2所示。服務(wù)器端創(chuàng)建監(jiān)聽套接字,并為它關(guān)聯(lián)一個本地地址(指定IP地址和端口號),然后進(jìn)入監(jiān)聽狀態(tài)準(zhǔn)備接受客戶的連接請求。為了接受客戶端的連接請求,服務(wù)器端必須調(diào)用accept函數(shù)??蛻舳藙?chuàng)建套接字后即可調(diào)用connect函數(shù)去試圖連接服務(wù)器監(jiān)聽套接字。當(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ù)器和客戶端程序舉例下面是最簡單的TCP服務(wù)器程序和TCP客戶端程序的例子。這兩個程序都是控制臺界面的Win32應(yīng)用程序,分別在配套光盤的TCPServer和TCPClient工程下。運(yùn)行服務(wù)器程序TCPServer,如果沒有錯誤發(fā)生,將在本地機(jī)器上的4567端口上等待客戶端的連接。如果沒有連接請求,服務(wù)器會一直處于休眠狀態(tài)。運(yùn)行服務(wù)器之后,再運(yùn)行客戶端程序TCPClient,其最終效果如圖2.3所示??蛻舳诉B接到了服務(wù)器,雙方套接字可以通信了。程序見TCPServer2.3Winsock編程詳解2.3.4UDP編程TCP由于可靠、穩(wěn)定的特點(diǎn)而被用在大部分場合,但它對系統(tǒng)資源要求比較高。UDP是一個簡單的面向數(shù)據(jù)報(bào)的傳輸層協(xié)議,又叫用戶數(shù)據(jù)報(bào)協(xié)議。它提供了無連接的、不可靠的數(shù)據(jù)傳輸服務(wù)。無連接是指它不像TCP那樣在通信前先與對方建立連接以確定對方的狀態(tài)。不可靠是指它直接按照指定IP地址和端口號將數(shù)據(jù)包發(fā)出去,如果對方不在線的話數(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í)也需要知道通信對端的地址信息。intrecvfrom(SOCKETs,charFAR*buf,intlen,intflags,structsockaddrFAR*from,intFAR*fromlen);這個函數(shù)比recv函數(shù)多出
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 煙草制品銷售合同調(diào)解
- 體育經(jīng)紀(jì)律師聘用協(xié)議
- 智能家居控制系統(tǒng)布線協(xié)議
- 房屋室內(nèi)裝飾施工合同
- 食醋公司總經(jīng)理聘用合同
- 社交高炮施工合同
- 衛(wèi)生打掃合同范例
- 塑料草皮購銷合同范例
- 公民代理 勞動合同
- 工作師徒合同評價(jià)
- 腳手架搭設(shè)與使用風(fēng)險(xiǎn)分析及管控措施
- 彩色簡約魚骨圖PPT圖表模板
- 經(jīng)纖維支氣管鏡氣管插管
- 初中英語常考改錯練習(xí)題(共十八類100題附參考答案-解析)
- 爐膛熱力計(jì)算
- 深圳高鐵總部項(xiàng)目遴選方案
- AQ-C1-19 安全教育記錄表(三級)
- 營銷中心物業(yè)服務(wù)標(biāo)準(zhǔn)講解
- 五年級閱讀指導(dǎo)課(課堂PPT)
- 廣東飼料項(xiàng)目建議書(參考范文)
- 液堿濃度、密度對照表
評論
0/150
提交評論