真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

網(wǎng)絡(luò)編程學(xué)習(xí)——基本UDP套接字編程

1 概述
TCP編寫應(yīng)用程序和使用UDP編寫應(yīng)用程序之間存在一些本質(zhì)差異,其原因在于這兩個(gè)傳輸層之間的差異:UDP是無連接不可靠的數(shù)據(jù)報(bào)協(xié)議,非常不同于TCP提供的面向連接的可靠字節(jié)流。使用UDP編寫的一些常見應(yīng)用程序由:DNS(域名系統(tǒng))、NFS(網(wǎng)絡(luò)文件系統(tǒng))和SNMP(簡單網(wǎng)絡(luò)管理協(xié)議)。
圖1-1給出了典型的UDP客戶/服務(wù)器程序函數(shù)調(diào)用??蛻舨慌c服務(wù)器建立連接,而是只管使用sendto函數(shù)給服務(wù)器發(fā)送數(shù)據(jù)報(bào),其中必須指定目的地(即服務(wù)器)的地址作為參數(shù)。類似地,服務(wù)器不接受來自客戶的連接,而是只管調(diào)用recvfrom函數(shù),等待來自某個(gè)客戶的數(shù)據(jù)到達(dá)。recfrom將與所接收的數(shù)據(jù)報(bào)一道返回客戶的協(xié)議地址,因此服務(wù)器可以把響應(yīng)發(fā)送給正確的客戶。

創(chuàng)新互聯(lián)長期為上千多家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺(tái),與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為順義企業(yè)提供專業(yè)的成都做網(wǎng)站、成都網(wǎng)站建設(shè),順義網(wǎng)站改版等技術(shù)服務(wù)。擁有10余年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開發(fā)。

UDP客戶/服務(wù)器程序所用的套接字函數(shù)
2 recvfrom和sendto函數(shù)
這兩個(gè)函數(shù)類似于標(biāo)準(zhǔn)的read和write函數(shù),不過需要三個(gè)額外的參數(shù)。
#include /*ReadNbytesintoBUFthroughsocketFD. IfADDRisnotNULL,fillin*ADDR_LENbytesofitwiththaaddressof thesender,andstoretheactualsizeoftheaddressin*ADDR_LEN. Returnsthenumberofbytesreador-1forerrors. Thisfunctionisacancellationpointandthereforenotmarkedwith __THROW.*/ externssize_trecvfrom(int__fd,void*__restrict__buf,size_t__n, int__flags,__SOCKADDR_ARG__addr, socklen_t*__restrict__addr_len); /*SendNbytesofBUFonsocketFDtopeerataddressADDR(whichis ADDR_LENbyteslong).Returnsthenumbersent,or-1forerrors. Thisfunctionisacancellationpointandthereforenotmarkedwith __THROW.*/ externssize_tsendto(int__fd,constvoid*__buf,size_t__n, int__flags,__CONST_SOCKADDR_ARG__addr, socklen_t__addr_len);
前三個(gè)參數(shù)__fd、__buf和__n等同于read和write函數(shù)的三個(gè)參數(shù):描述符、指向讀入或?qū)懗鼍彌_區(qū)的指針和讀寫字節(jié)數(shù)。
sendto的__addr參數(shù)指向一個(gè)含有數(shù)據(jù)接收者的協(xié)議地址(如IP地址及端口號(hào))的套接字地址結(jié)構(gòu),其大小由__addr_len參數(shù)指定。recvfrom的__addr參數(shù)指向一個(gè)由該函數(shù)在返回時(shí)填寫數(shù)據(jù)報(bào)發(fā)送者的協(xié)議地址的套接字地址結(jié)構(gòu),而在該套接字地址結(jié)構(gòu)中填寫的字節(jié)數(shù)則放在__addr_len參數(shù)所指的整數(shù)中返回給調(diào)用者。注意,sendto的最后一個(gè)參數(shù)是一個(gè)整數(shù)值,而recvfrom的最后一個(gè)參數(shù)是一個(gè)指向整數(shù)值的指針(即值-結(jié)果參數(shù))。
recvfrom的最后兩個(gè)參數(shù)類似于accept的最后兩個(gè)參數(shù):返回時(shí)其中套接字地址結(jié)構(gòu)的內(nèi)容告訴我們是誰發(fā)送了數(shù)據(jù)報(bào)(UDP情況下)或是誰發(fā)起了連接(TCP情況下)。sendto的最后兩個(gè)參數(shù)類似于connect的最后兩個(gè)參數(shù):調(diào)用時(shí)其中套接字地址結(jié)構(gòu)被我們填入數(shù)據(jù)報(bào)將發(fā)往(UDP情況下)或與之建立連接(TCP情況下)的協(xié)議地址。
這兩個(gè)函數(shù)都把所讀寫數(shù)據(jù)的長度作為函數(shù)返回值。在recvfrom使用數(shù)據(jù)報(bào)協(xié)議的典型用途中,返回值就是所接收數(shù)據(jù)報(bào)中的用戶數(shù)據(jù)量。
寫一個(gè)長度為0的數(shù)據(jù)報(bào)是可行的。在UDP情況下,這會(huì)形成一個(gè)只包含一個(gè)IP首部(對(duì)于IPv4通常是20字節(jié),對(duì)于IPv6通常是40字節(jié))和一個(gè)8字節(jié)UDP首部而沒有數(shù)據(jù)的IP數(shù)據(jù)報(bào)。這也意味著對(duì)于數(shù)據(jù)報(bào)協(xié)議,recvfrom返回0值是可接受的:它并不像TCP套接字上read返回0值那樣表示對(duì)端已關(guān)閉連接。既然UDP是無連接的,因此也就沒有諸如關(guān)閉一個(gè)UDP連接之類事情。
如果recvfrom的__addr參數(shù)是一個(gè)空指針,那么相應(yīng)的長度參數(shù)(addrlen)也必須是一個(gè)空指針,表示我們并不關(guān)心數(shù)據(jù)發(fā)送者的協(xié)議地址。
recvfrom和sendto都可用于TCP,盡管通常沒有理由這樣做。
3 UDP回射服務(wù)器程序:main函數(shù)
我們的UDP客戶程序和服務(wù)器程序依循圖1-1中所示的函數(shù)調(diào)用流程。圖1-2描述了它們使用的函數(shù)。
使用UDP的簡單回射客戶/服務(wù)器
下面是main函數(shù)。
#defineSERV_PORT9877 intmain(intargc,char**argv) { intsockfd; structsockaddr_inservaddr,cliaddr; //我們通過將socket函數(shù)的第二個(gè)參數(shù)指定為SOCK_DGRAM(IPv4協(xié)議中的數(shù)據(jù)報(bào)套接字)創(chuàng)建一個(gè)UDP套接字。正如 //TCP服務(wù)器程序的例子,用于bind的服務(wù)器IPv4地址被指定為INADDR_ANY,而服務(wù)器的眾所周知端口是9877 sockfd=socket(AF_INET,SCOK_DGRAM,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=htonl(INADDR_ANY); seraddr.sin_port=htons(SERV_PORT); if((bind(sockfd,(structsockaddr*)&servaddr,sizeof(servaddr)))<0) { printf("binderror!n"); return-1; } //接著調(diào)用函數(shù)dg_echo來執(zhí)行服務(wù)器的處理工作 dg_echo(sockfd,(structsockaddr*)&servaddr,sizeof(cliaddr)); } 4 UDP回射服務(wù)器程序:dg_echo函數(shù)
下面給出dg_echo函數(shù)。
voiddg_echo(intsockfd,structsockaddr*pcliaddr,socklen_tclilen) { intn; socklen_tlen; charmesg[MAXLINE]; //該函數(shù)是一個(gè)簡單的循環(huán),它使用recvfrom讀入下一個(gè)到達(dá)服務(wù)器端口的數(shù)據(jù)報(bào),再使用sendto把它發(fā)送回發(fā)送者。 for(;;) { len=clilen; n=recvfrom(sockfd,mesg,MAXLINE,0,pcliaddr,&len); sendto(sockfd,mesg,n,0,pcliaddr,len); } }
首先,該函數(shù)永不終止,因?yàn)閁DP是一個(gè)無連接的協(xié)議,它沒有像TCP中EOF之類的東西。
其次,該函數(shù)提供的是一個(gè)迭代服務(wù)器(iterative server),而不是像TCP服務(wù)器那樣可以提供一個(gè)并發(fā)服務(wù)器。其中沒有對(duì)fork的調(diào)用,因此單個(gè)服務(wù)器進(jìn)程就得處理所有客戶。一般來說,大多數(shù)TCP服務(wù)器是并發(fā)的,而大多數(shù)UDP服務(wù)器是迭代的。
對(duì)于本套接字,UDP層隱含有排隊(duì)發(fā)生。事實(shí)上每個(gè)UDP套接字都有一個(gè)接收緩沖區(qū),到達(dá)該套接字的每個(gè)數(shù)據(jù)報(bào)都進(jìn)入這個(gè)套接字接收緩沖區(qū)。當(dāng)進(jìn)程調(diào)用recvfrom時(shí),緩沖區(qū)中的下一個(gè)數(shù)據(jù)報(bào)以FIFO(先入先出)順序返回給進(jìn)程。這樣,在進(jìn)程能夠讀該套接字中任何已排好的數(shù)據(jù)報(bào)之前,如果有多個(gè)數(shù)據(jù)報(bào)到達(dá)該套接字,那么相繼到達(dá)的數(shù)據(jù)報(bào)僅僅加到該套接字的接收緩沖區(qū)。然而這個(gè)緩沖區(qū)的大小是有限的。可以用SO_RECVNUF套接字選項(xiàng)來改變大小。
總結(jié)了TCP客戶/服務(wù)器在兩個(gè)客戶與服務(wù)器建立連接時(shí)的情形。
兩個(gè)客戶的TCP客戶/服務(wù)器小結(jié)
服務(wù)器主機(jī)上有兩個(gè)已連接套接字,其中每一個(gè)都由各自的套接字接收緩沖區(qū)。
展示了兩個(gè)客戶發(fā)送數(shù)據(jù)報(bào)到UDP服務(wù)器的情形。
兩個(gè)客戶的UDP客戶/服務(wù)器小結(jié)
其中只有一個(gè)服務(wù)器進(jìn)程,它僅有的單個(gè)套接字用于接收所有到達(dá)的數(shù)據(jù)報(bào)并發(fā)回所有的響應(yīng)。該套接字有一個(gè)接收緩沖區(qū)用來存放所到達(dá)的數(shù)據(jù)報(bào)。
上面的main函數(shù)是協(xié)議相關(guān)的(它創(chuàng)建一個(gè)AF_INET協(xié)議的套接字,分配并初始化一個(gè)IPv4套接字的地址結(jié)構(gòu)),而dg_echo函數(shù)是協(xié)議無關(guān)的。dg_echo協(xié)議無關(guān)理由如下:調(diào)用者必須分配一個(gè)正確大小的套接字地址結(jié)構(gòu),且指向該結(jié)構(gòu)的指針和該結(jié)構(gòu)的大小都必須作為參數(shù)傳遞給dg_echo。dg_echo絕不查看這個(gè)協(xié)議相關(guān)結(jié)構(gòu)的內(nèi)容,而是簡單地把一個(gè)指向該結(jié)構(gòu)的指針傳遞給recvfrom和senfto。recvfrom返回時(shí)把客戶的IP地址和端口號(hào)填入該結(jié)構(gòu),而隨后作為目的地址傳遞給sendto的又是同一個(gè)指針(pcliaddr),這樣所接收的任何數(shù)據(jù)報(bào)就被回射給發(fā)送該數(shù)據(jù)報(bào)的客戶。
5 UDP回射客戶程序:main函數(shù)
UDP客戶程序的main函數(shù)。
intmain(intargc,char**argv) { intsockfd; structsockaddr_inservaddr; if(argc!=2) { printf("usage:udpclin"); exit(1); } //把服務(wù)器的IP地址和端口號(hào)填入一個(gè)IPv4的套接字地址結(jié)構(gòu)。該結(jié)構(gòu)將傳遞給dg_cli函數(shù),以指明數(shù)據(jù)報(bào)將發(fā)往何處。 bzero(&servaddr,sizeof(servaddr)); servaddr.sin_famliy=AF_INET; servaddr.sin_port=htons(SERV_PORT); inet_pton(AF_INET,argv[1],&servaddr.sin_addr); sockfd=socket(AF_INET,SOCK_DGRAM,0); dg_cli(stdin,sockfd,(structsockaddr*)&servaddr,sizeof(servaddr)); exit(0); } 6 UDP回射客戶程序:dg_cli函數(shù)
下面是dg_cli函數(shù),它執(zhí)行客戶的大部分工作。
voiddg_cli(FILE*fp,intsockfd,conststructsockaddr*pservaddr,socklen_tservlen) { intn; charsendline[MAXLINE],recvline[MAXLINE+1]; //客戶處理循環(huán)有四個(gè)步驟:使用fgets從標(biāo)準(zhǔn)輸入讀入一個(gè)文本行,使用sendto將該文本行發(fā)送給服務(wù)器,使用 //recvfrom讀回服務(wù)器的回射,使用fputs把回射的文本行顯示到標(biāo)準(zhǔn)輸出。 while(fgets(sendline,MANLINE,fd)!=NULL) { sendto(sockfd,sendline,strlen(sendline),0,pservaddr,servlen); n=recvfrom(sockfd,recvline,MAXLINE,0,NULL,NULL); recvline[n]=0;//nullterminate fputs(recvline,stdout); } }
7 數(shù)據(jù)報(bào)的丟失
這個(gè)UDP客戶/服務(wù)器例子是不可靠的。如果一個(gè)客戶數(shù)據(jù)報(bào)丟失(譬如說,被客戶主機(jī)與服務(wù)器主機(jī)之間的某個(gè)路由器丟棄),客戶將永遠(yuǎn)阻塞在dg_cli函數(shù)中的recvfrom調(diào)用,等待一個(gè)永遠(yuǎn)不會(huì)到達(dá)的服務(wù)器應(yīng)答。防止這樣永久阻塞的一般方法是給客戶的recvfrom調(diào)用設(shè)置一個(gè)超時(shí)。
然而僅僅設(shè)置超時(shí)并不是完整的解決辦法,因?yàn)槲覀儾荒苤莱瑫r(shí)的原因。
8 驗(yàn)證接收到的響應(yīng)
客戶臨時(shí)端口號(hào)的任何進(jìn)程都可往客戶發(fā)送數(shù)據(jù)報(bào),而且這些數(shù)據(jù)報(bào)會(huì)與正常的服務(wù)器應(yīng)答混雜。解決辦法是把recvfrom調(diào)用以返回?cái)?shù)據(jù)報(bào)發(fā)送者的IP地址和端口號(hào),保留來自數(shù)據(jù)報(bào)所發(fā)往服務(wù)器的應(yīng)答,而忽略任何其他數(shù)據(jù)報(bào)。
首先把main函數(shù)改為標(biāo)準(zhǔn)回射服務(wù)器。
servaddr.sin_port=htons(7);
我們接著重寫dg_cli函數(shù)以分配另一個(gè)套接字地址結(jié)構(gòu)用于存放由recvfrom返回的結(jié)構(gòu)。
voiddg_cli(FILE*fp,intsockfd,conststructsockaddr*pservaddr,socklen_tservlen) { intn; charsendline[MAXLINE],recvline[MAXLINE+1]; socklen_tlen; structsockaddr*preply_addr; preply_addr=malloc(servlen); while(fgets(sendline,MAXLINE,fp)!=NULL) { sendto(sockfd,sendline,strlen(sendline),0,pservaddr,servlen); n=recvfrom(sockfd,recvline,MAXLINE,0,preply_addr,&len); if(len!=servlen||memcmp(pservaddr,preply_addr,len)!=0) { printf("replyfrom%s(ignored)n",sock_ntop(preply_addr,len)); continue; } recvline[n]=0;//nullterminate fputs(recvline,stdout); } }


新聞名稱:網(wǎng)絡(luò)編程學(xué)習(xí)——基本UDP套接字編程
網(wǎng)頁網(wǎng)址:http://weahome.cn/article/cgpesp.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部