内射老阿姨1区2区3区4区_久久精品人人做人人爽电影蜜月_久久国产精品亚洲77777_99精品又大又爽又粗少妇毛片

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

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

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

UDP客戶(hù)/服務(wù)器程序所用的套接字函數(shù)
2 recvfrom和sendto函數(shù)
這兩個(gè)函數(shù)類(lèi)似于標(biāo)準(zhǔn)的read和write函數(shù),不過(guò)需要三個(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ū)的指針和讀寫(xiě)字節(jié)數(shù)。
sendto的__addr參數(shù)指向一個(gè)含有數(shù)據(jù)接收者的協(xié)議地址(如IP地址及端口號(hào))的套接字地址結(jié)構(gòu),其大小由__addr_len參數(shù)指定。recvfrom的__addr參數(shù)指向一個(gè)由該函數(shù)在返回時(shí)填寫(xiě)數(shù)據(jù)報(bào)發(fā)送者的協(xié)議地址的套接字地址結(jié)構(gòu),而在該套接字地址結(jié)構(gòu)中填寫(xiě)的字節(jié)數(shù)則放在__addr_len參數(shù)所指的整數(shù)中返回給調(diào)用者。注意,sendto的最后一個(gè)參數(shù)是一個(gè)整數(shù)值,而recvfrom的最后一個(gè)參數(shù)是一個(gè)指向整數(shù)值的指針(即值-結(jié)果參數(shù))。
recvfrom的最后兩個(gè)參數(shù)類(lèi)似于accept的最后兩個(gè)參數(shù):返回時(shí)其中套接字地址結(jié)構(gòu)的內(nèi)容告訴我們是誰(shuí)發(fā)送了數(shù)據(jù)報(bào)(UDP情況下)或是誰(shuí)發(fā)起了連接(TCP情況下)。sendto的最后兩個(gè)參數(shù)類(lèi)似于connect的最后兩個(gè)參數(shù):調(diào)用時(shí)其中套接字地址結(jié)構(gòu)被我們填入數(shù)據(jù)報(bào)將發(fā)往(UDP情況下)或與之建立連接(TCP情況下)的協(xié)議地址。
這兩個(gè)函數(shù)都把所讀寫(xiě)數(shù)據(jù)的長(zhǎng)度作為函數(shù)返回值。在recvfrom使用數(shù)據(jù)報(bào)協(xié)議的典型用途中,返回值就是所接收數(shù)據(jù)報(bào)中的用戶(hù)數(shù)據(jù)量。
寫(xiě)一個(gè)長(zhǎng)度為0的數(shù)據(jù)報(bào)是可行的。在UDP情況下,這會(huì)形成一個(gè)只包含一個(gè)IP首部(對(duì)于IPv4通常是20字節(jié),對(duì)于IPv6通常是40字節(jié))和一個(gè)8字節(jié)UDP首部而沒(méi)有數(shù)據(jù)的IP數(shù)據(jù)報(bào)。這也意味著對(duì)于數(shù)據(jù)報(bào)協(xié)議,recvfrom返回0值是可接受的:它并不像TCP套接字上read返回0值那樣表示對(duì)端已關(guān)閉連接。既然UDP是無(wú)連接的,因此也就沒(méi)有諸如關(guān)閉一個(gè)UDP連接之類(lèi)事情。
如果recvfrom的__addr參數(shù)是一個(gè)空指針,那么相應(yīng)的長(zhǎng)度參數(shù)(addrlen)也必須是一個(gè)空指針,表示我們并不關(guān)心數(shù)據(jù)發(fā)送者的協(xié)議地址。
recvfrom和sendto都可用于TCP,盡管通常沒(méi)有理由這樣做。
3 UDP回射服務(wù)器程序:main函數(shù)
我們的UDP客戶(hù)程序和服務(wù)器程序依循圖1-1中所示的函數(shù)調(diào)用流程。圖1-2描述了它們使用的函數(shù)。
使用UDP的簡(jiǎn)單回射客戶(hù)/服務(wù)器
下面是main函數(shù)。
#defineSERV_PORT9877 intmain(intargc,char**argv) { intsockfd; structsockaddr_inservaddr,cliaddr; //我們通過(guò)將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來(lái)執(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è)簡(jiǎn)單的循環(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è)無(wú)連接的協(xié)議,它沒(méi)有像TCP中EOF之類(lèi)的東西。
其次,該函數(shù)提供的是一個(gè)迭代服務(wù)器(iterative server),而不是像TCP服務(wù)器那樣可以提供一個(gè)并發(fā)服務(wù)器。其中沒(méi)有對(duì)fork的調(diào)用,因此單個(gè)服務(wù)器進(jìn)程就得處理所有客戶(hù)。一般來(lái)說(shuō),大多數(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ū)的大小是有限的??梢杂肧O_RECVNUF套接字選項(xiàng)來(lái)改變大小。
總結(jié)了TCP客戶(hù)/服務(wù)器在兩個(gè)客戶(hù)與服務(wù)器建立連接時(shí)的情形。
兩個(gè)客戶(hù)的TCP客戶(hù)/服務(wù)器小結(jié)
服務(wù)器主機(jī)上有兩個(gè)已連接套接字,其中每一個(gè)都由各自的套接字接收緩沖區(qū)。
展示了兩個(gè)客戶(hù)發(fā)送數(shù)據(jù)報(bào)到UDP服務(wù)器的情形。
兩個(gè)客戶(hù)的UDP客戶(hù)/服務(wù)器小結(jié)
其中只有一個(gè)服務(wù)器進(jìn)程,它僅有的單個(gè)套接字用于接收所有到達(dá)的數(shù)據(jù)報(bào)并發(fā)回所有的響應(yīng)。該套接字有一個(gè)接收緩沖區(qū)用來(lái)存放所到達(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é)議無(wú)關(guān)的。dg_echo協(xié)議無(wú)關(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)容,而是簡(jiǎn)單地把一個(gè)指向該結(jié)構(gòu)的指針傳遞給recvfrom和senfto。recvfrom返回時(shí)把客戶(hù)的IP地址和端口號(hào)填入該結(jié)構(gòu),而隨后作為目的地址傳遞給sendto的又是同一個(gè)指針(pcliaddr),這樣所接收的任何數(shù)據(jù)報(bào)就被回射給發(fā)送該數(shù)據(jù)報(bào)的客戶(hù)。
5 UDP回射客戶(hù)程序:main函數(shù)
UDP客戶(hù)程序的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回射客戶(hù)程序:dg_cli函數(shù)
下面是dg_cli函數(shù),它執(zhí)行客戶(hù)的大部分工作。
voiddg_cli(FILE*fp,intsockfd,conststructsockaddr*pservaddr,socklen_tservlen) { intn; charsendline[MAXLINE],recvline[MAXLINE+1]; //客戶(hù)處理循環(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客戶(hù)/服務(wù)器例子是不可靠的。如果一個(gè)客戶(hù)數(shù)據(jù)報(bào)丟失(譬如說(shuō),被客戶(hù)主機(jī)與服務(wù)器主機(jī)之間的某個(gè)路由器丟棄),客戶(hù)將永遠(yuǎn)阻塞在dg_cli函數(shù)中的recvfrom調(diào)用,等待一個(gè)永遠(yuǎn)不會(huì)到達(dá)的服務(wù)器應(yīng)答。防止這樣永久阻塞的一般方法是給客戶(hù)的recvfrom調(diào)用設(shè)置一個(gè)超時(shí)。
然而僅僅設(shè)置超時(shí)并不是完整的解決辦法,因?yàn)槲覀儾荒苤莱瑫r(shí)的原因。
8 驗(yàn)證接收到的響應(yīng)
客戶(hù)臨時(shí)端口號(hào)的任何進(jìn)程都可往客戶(hù)發(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),保留來(lái)自數(shù)據(jù)報(bào)所發(fā)往服務(wù)器的應(yīng)答,而忽略任何其他數(shù)據(jù)報(bào)。
首先把main函數(shù)改為標(biāo)準(zhǔn)回射服務(wù)器。
servaddr.sin_port=htons(7);
我們接著重寫(xiě)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); } }

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

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

廣告

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

成都app開(kāi)發(fā)公司
丁青县| 清水河县| 武定县| 石柱| 望奎县| 三河市| 遂宁市| 宿州市| 航空| 岳普湖县| 化州市| 东城区| 上思县| 福泉市| 丹东市| 高安市| 泸溪县| 拉萨市| 宝兴县| 大姚县| 营山县| 百色市| 桦川县| 灵武市| 云林县| 广汉市| 万宁市| 青神县| 佛冈县| 焉耆| 苍梧县| 阜宁县| 岳阳县| 济阳县| 黎平县| 寿阳县| 邹城市| 贺州市| 息烽县| 东源县| 齐齐哈尔市|