欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

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

1 概述
TCP編寫應(yīng)用程序和使用UDP編寫應(yīng)用程序之間存在一些本質(zhì)差異,其原因在于這兩個傳輸層之間的差異:UDP是無連接不可靠的數(shù)據(jù)報協(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)用。客戶不與服務(wù)器建立連接,而是只管使用sendto函數(shù)給服務(wù)器發(fā)送數(shù)據(jù)報,其中必須指定目的地(即服務(wù)器)的地址作為參數(shù)。類似地,服務(wù)器不接受來自客戶的連接,而是只管調(diào)用recvfrom函數(shù),等待來自某個客戶的數(shù)據(jù)到達(dá)。recfrom將與所接收的數(shù)據(jù)報一道返回客戶的協(xié)議地址,因此服務(wù)器可以把響應(yīng)發(fā)送給正確的客戶。

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

UDP客戶/服務(wù)器程序所用的套接字函數(shù)
2 recvfrom和sendto函數(shù)
這兩個函數(shù)類似于標(biāo)準(zhǔn)的read和write函數(shù),不過需要三個額外的參數(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);
前三個參數(shù)__fd、__buf和__n等同于read和write函數(shù)的三個參數(shù):描述符、指向讀入或?qū)懗鼍彌_區(qū)的指針和讀寫字節(jié)數(shù)。
sendto的__addr參數(shù)指向一個含有數(shù)據(jù)接收者的協(xié)議地址(如IP地址及端口號)的套接字地址結(jié)構(gòu),其大小由__addr_len參數(shù)指定。recvfrom的__addr參數(shù)指向一個由該函數(shù)在返回時填寫數(shù)據(jù)報發(fā)送者的協(xié)議地址的套接字地址結(jié)構(gòu),而在該套接字地址結(jié)構(gòu)中填寫的字節(jié)數(shù)則放在__addr_len參數(shù)所指的整數(shù)中返回給調(diào)用者。注意,sendto的最后一個參數(shù)是一個整數(shù)值,而recvfrom的最后一個參數(shù)是一個指向整數(shù)值的指針(即值-結(jié)果參數(shù))。
recvfrom的最后兩個參數(shù)類似于accept的最后兩個參數(shù):返回時其中套接字地址結(jié)構(gòu)的內(nèi)容告訴我們是誰發(fā)送了數(shù)據(jù)報(UDP情況下)或是誰發(fā)起了連接(TCP情況下)。sendto的最后兩個參數(shù)類似于connect的最后兩個參數(shù):調(diào)用時其中套接字地址結(jié)構(gòu)被我們填入數(shù)據(jù)報將發(fā)往(UDP情況下)或與之建立連接(TCP情況下)的協(xié)議地址。
這兩個函數(shù)都把所讀寫數(shù)據(jù)的長度作為函數(shù)返回值。在recvfrom使用數(shù)據(jù)報協(xié)議的典型用途中,返回值就是所接收數(shù)據(jù)報中的用戶數(shù)據(jù)量。
寫一個長度為0的數(shù)據(jù)報是可行的。在UDP情況下,這會形成一個只包含一個IP首部(對于IPv4通常是20字節(jié),對于IPv6通常是40字節(jié))和一個8字節(jié)UDP首部而沒有數(shù)據(jù)的IP數(shù)據(jù)報。這也意味著對于數(shù)據(jù)報協(xié)議,recvfrom返回0值是可接受的:它并不像TCP套接字上read返回0值那樣表示對端已關(guān)閉連接。既然UDP是無連接的,因此也就沒有諸如關(guān)閉一個UDP連接之類事情。
如果recvfrom的__addr參數(shù)是一個空指針,那么相應(yīng)的長度參數(shù)(addrlen)也必須是一個空指針,表示我們并不關(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ù)的第二個參數(shù)指定為SOCK_DGRAM(IPv4協(xié)議中的數(shù)據(jù)報套接字)創(chuàng)建一個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ù)是一個簡單的循環(huán),它使用recvfrom讀入下一個到達(dá)服務(wù)器端口的數(shù)據(jù)報,再使用sendto把它發(fā)送回發(fā)送者。 for(;;) { len=clilen; n=recvfrom(sockfd,mesg,MAXLINE,0,pcliaddr,&len); sendto(sockfd,mesg,n,0,pcliaddr,len); } }
首先,該函數(shù)永不終止,因為UDP是一個無連接的協(xié)議,它沒有像TCP中EOF之類的東西。
其次,該函數(shù)提供的是一個迭代服務(wù)器(iterative server),而不是像TCP服務(wù)器那樣可以提供一個并發(fā)服務(wù)器。其中沒有對fork的調(diào)用,因此單個服務(wù)器進(jìn)程就得處理所有客戶。一般來說,大多數(shù)TCP服務(wù)器是并發(fā)的,而大多數(shù)UDP服務(wù)器是迭代的。
對于本套接字,UDP層隱含有排隊發(fā)生。事實上每個UDP套接字都有一個接收緩沖區(qū),到達(dá)該套接字的每個數(shù)據(jù)報都進(jìn)入這個套接字接收緩沖區(qū)。當(dāng)進(jìn)程調(diào)用recvfrom時,緩沖區(qū)中的下一個數(shù)據(jù)報以FIFO(先入先出)順序返回給進(jìn)程。這樣,在進(jìn)程能夠讀該套接字中任何已排好的數(shù)據(jù)報之前,如果有多個數(shù)據(jù)報到達(dá)該套接字,那么相繼到達(dá)的數(shù)據(jù)報僅僅加到該套接字的接收緩沖區(qū)。然而這個緩沖區(qū)的大小是有限的。可以用SO_RECVNUF套接字選項來改變大小。
總結(jié)了TCP客戶/服務(wù)器在兩個客戶與服務(wù)器建立連接時的情形。
兩個客戶的TCP客戶/服務(wù)器小結(jié)
服務(wù)器主機(jī)上有兩個已連接套接字,其中每一個都由各自的套接字接收緩沖區(qū)。
展示了兩個客戶發(fā)送數(shù)據(jù)報到UDP服務(wù)器的情形。
兩個客戶的UDP客戶/服務(wù)器小結(jié)
其中只有一個服務(wù)器進(jìn)程,它僅有的單個套接字用于接收所有到達(dá)的數(shù)據(jù)報并發(fā)回所有的響應(yīng)。該套接字有一個接收緩沖區(qū)用來存放所到達(dá)的數(shù)據(jù)報。
上面的main函數(shù)是協(xié)議相關(guān)的(它創(chuàng)建一個AF_INET協(xié)議的套接字,分配并初始化一個IPv4套接字的地址結(jié)構(gòu)),而dg_echo函數(shù)是協(xié)議無關(guān)的。dg_echo協(xié)議無關(guān)理由如下:調(diào)用者必須分配一個正確大小的套接字地址結(jié)構(gòu),且指向該結(jié)構(gòu)的指針和該結(jié)構(gòu)的大小都必須作為參數(shù)傳遞給dg_echo。dg_echo絕不查看這個協(xié)議相關(guān)結(jié)構(gòu)的內(nèi)容,而是簡單地把一個指向該結(jié)構(gòu)的指針傳遞給recvfrom和senfto。recvfrom返回時把客戶的IP地址和端口號填入該結(jié)構(gòu),而隨后作為目的地址傳遞給sendto的又是同一個指針(pcliaddr),這樣所接收的任何數(shù)據(jù)報就被回射給發(fā)送該數(shù)據(jù)報的客戶。
5 UDP回射客戶程序:main函數(shù)
UDP客戶程序的main函數(shù)。
intmain(intargc,char**argv) { intsockfd; structsockaddr_inservaddr; if(argc!=2) { printf("usage:udpclin"); exit(1); } //把服務(wù)器的IP地址和端口號填入一個IPv4的套接字地址結(jié)構(gòu)。該結(jié)構(gòu)將傳遞給dg_cli函數(shù),以指明數(shù)據(jù)報將發(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)有四個步驟:使用fgets從標(biāo)準(zhǔn)輸入讀入一個文本行,使用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ù)報的丟失
這個UDP客戶/服務(wù)器例子是不可靠的。如果一個客戶數(shù)據(jù)報丟失(譬如說,被客戶主機(jī)與服務(wù)器主機(jī)之間的某個路由器丟棄),客戶將永遠(yuǎn)阻塞在dg_cli函數(shù)中的recvfrom調(diào)用,等待一個永遠(yuǎn)不會到達(dá)的服務(wù)器應(yīng)答。防止這樣永久阻塞的一般方法是給客戶的recvfrom調(diào)用設(shè)置一個超時。
然而僅僅設(shè)置超時并不是完整的解決辦法,因為我們不能知道超時的原因。
8 驗證接收到的響應(yīng)
客戶臨時端口號的任何進(jìn)程都可往客戶發(fā)送數(shù)據(jù)報,而且這些數(shù)據(jù)報會與正常的服務(wù)器應(yīng)答混雜。解決辦法是把recvfrom調(diào)用以返回數(shù)據(jù)報發(fā)送者的IP地址和端口號,保留來自數(shù)據(jù)報所發(fā)往服務(wù)器的應(yīng)答,而忽略任何其他數(shù)據(jù)報。
首先把main函數(shù)改為標(biāo)準(zhǔn)回射服務(wù)器。
servaddr.sin_port=htons(7);
我們接著重寫dg_cli函數(shù)以分配另一個套接字地址結(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); } }

當(dāng)前文章:網(wǎng)絡(luò)編程學(xué)習(xí)——基本UDP套接字編程
分享網(wǎng)址:http://chinadenli.net/article38/cgpesp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供服務(wù)器托管網(wǎng)站收錄品牌網(wǎng)站制作網(wǎng)站策劃虛擬主機(jī)建站公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都app開發(fā)公司