成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

技術(shù)分析:基本 UDP 套接字編程

網(wǎng)絡(luò) 網(wǎng)絡(luò)管理
UDP 協(xié)議和 TCP 協(xié)議不同,它是一種面向無連接、不可靠的傳輸層協(xié)議。在基于 UDP 套接字編程中,數(shù)據(jù)傳輸可用函數(shù) sendto 和 recvfrom。

[[124415]]

UDP 協(xié)議和 TCP 協(xié)議不同,它是一種面向無連接、不可靠的傳輸層協(xié)議。在基于 UDP 套接字編程中,數(shù)據(jù)傳輸可用函數(shù) sendto 和 recvfrom。以下是基本 UDP 套接字編程過程:

 

 

sendto 與 recvfrom 函數(shù)

這兩個函數(shù)的功能類似于 write 和 read 函數(shù),可用無連接的套接字編程。其定義如下:

  1. /* 函數(shù)功能:發(fā)送數(shù)據(jù);  
  2.  * 返回值:若成功則返回已發(fā)送的字節(jié)數(shù),若出錯則返回-1;  
  3.  * 函數(shù)原型:  
  4.  */   
  5. #include <sys/socket.h>   
  6.    
  7. ssize_t sendto(int sockfd, void *buff, size_t nbytes, int flags,   
  8.                 const struct sockaddr *destaddr, socklen_t addrlen);   
  9.    
  10. /* 說明:  
  11.  * 該函數(shù)功能類似于write函數(shù),除了有標(biāo)識符flags和目的地址信息之外,其他參數(shù)一樣;  
  12.  *  
  13.  * flags標(biāo)識符取值如下:  
  14.  * (1)MSG_DONTROUTE   勿將數(shù)據(jù)路由出本地網(wǎng)絡(luò)  
  15.  * (2)MSG_DONTWAIT    允許非阻塞操作  
  16.  * (3)MSG_EOR         如果協(xié)議支持,此為記錄結(jié)束  
  17.  * (4)MSG_OOB         如果協(xié)議支持,發(fā)送帶外數(shù)據(jù)  
  18.  *  
  19.  * 若sendto成功,則只是表示已將數(shù)據(jù)無錯誤的發(fā)送到網(wǎng)絡(luò),并不能保證正確到達(dá)對端;  
  20.  * 該函數(shù)通過指定目標(biāo)地址允許在無連接的套接字之間發(fā)送數(shù)據(jù)(例如UDP套接字);  
  21.  */   
  22.    
  23.  /* 函數(shù)功能:接收數(shù)據(jù);  
  24.   * 返回值:以字節(jié)計(jì)數(shù)的消息長度,若無可用消息或?qū)Ψ揭呀?jīng)按序結(jié)束則返回0,若出錯則返回-1;  
  25.   * 函數(shù)原型:  
  26.   */   
  27. #include <sys/socket.h>   
  28.    
  29. ssize_t recvfrom(int sockfd, void *buff, size_t nbytes, int flags,   
  30.                 struct sockaddr *addr, socklen_t *addrlen);   
  31.  /* 說明:  
  32.   * 該函數(shù)功能與read類似;  
  33.   * 若addr為非空時,它將包含數(shù)據(jù)發(fā)送者的套接字地址;  
  34.   *  
  35.   * flags標(biāo)識符取值如下:  
  36.   * (1)MSG_WAITALL     等待所有數(shù)據(jù)可用  
  37.   * (2)MSG_DONTWAIT    允許非阻塞操作  
  38.   * (3)MSG_PEEK        查看已讀取的數(shù)據(jù)  
  39.   * (4)MSG_OOB         如果協(xié)議支持,發(fā)送帶外數(shù)據(jù)  
  40.   */   

基于 UDP 套接字編程

下面我們使用 UDP 協(xié)議實(shí)現(xiàn)簡單的功能,客戶端從標(biāo)準(zhǔn)輸入讀取數(shù)據(jù)并把它發(fā)送給服務(wù)器,服務(wù)器接收到數(shù)據(jù)并把該數(shù)據(jù)回射給客戶端,然后客戶端收到從服務(wù)器回射的數(shù)據(jù)把它顯示到標(biāo)準(zhǔn)輸出。其功能實(shí)現(xiàn)如下圖所示:

 

 

服務(wù)器程序

  1. /* UDP 服務(wù)器 */   
  2. #include <string.h>   
  3. #include <stdio.h>   
  4. #include <unistd.h>   
  5. #include <stdlib.h>   
  6. #include <sys/socket.h>   
  7. #include <netinet/in.h>   
  8.    
  9. #define SERV_PORT 9877 /* 通用端口號 */   
  10.    
  11. extern void err_sys(const char *, ...);   
  12. extern void dg_echo(int sockfd, struct sockaddr *addr, socklen_t addrlen);   
  13.    
  14. int main(int argc, char **argv)   
  15. {   
  16.     int sockfd;   
  17.     int err;   
  18.     struct sockaddr_in servaddr, cliaddr;   
  19.    
  20.     /* 初始化服務(wù)器地址信息 */   
  21.     bzero(&servaddr, sizeof(servaddr));   
  22.     servaddr.sin_family = AF_INET;   
  23.     servaddr.sin_port = htons(SERV_PORT);   
  24.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);   
  25.    
  26.     /* 創(chuàng)建套接字,并將服務(wù)器地址綁定到該套接字上 */   
  27.     if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)   
  28.         err_sys("socket error");   
  29.     err =bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));   
  30.     if(err < 0)   
  31.         err_sys("bind error");   
  32.     /* 服務(wù)器處理函數(shù):讀取套接字文本行,并把它回射給客戶端 */   
  33.     dg_echo(sockfd, (struct sockaddr*) &cliaddr, sizeof(cliaddr));   
  34.    
  35. }   

處理函數(shù)

  1. #include    "unp.h"   
  2.    
  3. void   
  4. dg_echo(int sockfd, SA *pcliaddr, socklen_t clilen)   
  5. {   
  6.     int         n;   
  7.     socklen_t   len;   
  8.     char        mesg[MAXLINE];   
  9.    
  10.     for ( ; ; ) {   
  11.         len = clilen;   
  12.         n = Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);   
  13.    
  14.         Sendto(sockfd, mesg, n, 0, pcliaddr, len);   
  15.     }   
  16. }   

#p#客戶端程序

  1. /* UDP 客戶端 */   
  2. #include <string.h>   
  3. #include <stdio.h>   
  4. #include <unistd.h>   
  5. #include <stdlib.h>   
  6. #include <sys/socket.h>   
  7. #include <netinet/in.h>   
  8. #include <arpa/inet.h>   
  9.    
  10. #define SERV_PORT 9877 /* 通用端口號 */   
  11.    
  12. extern void err_sys(const char *, ...);   
  13. extern void err_quit(const char *, ...);   
  14. extern void dg_cli(FILE *fd, int sockfd, struct sockaddr *addr, socklen_t addrlen);   
  15.    
  16. int main(int argc, char **argv)   
  17. {   
  18.     int                 sockfd;   
  19.     struct sockaddr_in  servaddr;   
  20.    
  21.     if (argc != 2)   
  22.         err_quit("usage: udpcli <IPaddress>");   
  23.    
  24.     bzero(&servaddr, sizeof(servaddr));   
  25.     servaddr.sin_family = AF_INET;   
  26.     servaddr.sin_port = htons(SERV_PORT);   
  27.     inet_pton(AF_INET, argv[1], &servaddr.sin_addr);   
  28.    
  29.     if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)   
  30.         err_sys("socket err");   
  31. /* 客戶端處理函數(shù):從標(biāo)準(zhǔn)輸入讀入文本行,發(fā)送給服務(wù)器;接收來自服務(wù)器的回射文本,并把它顯示到標(biāo)準(zhǔn)輸出 */   
  32.     dg_cli(stdin, sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));   
  33.    
  34.     exit(0);   
  35. }   

客戶端處理函數(shù)

  1. #include    "unp.h"   
  2.    
  3. void   
  4. dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)   
  5. {   
  6.     int n;   
  7.     char    sendline[MAXLINE], recvline[MAXLINE + 1];   
  8.    
  9.     while (Fgets(sendline, MAXLINE, fp) != NULL) {   
  10. /* 把從標(biāo)準(zhǔn)輸入讀取的文本行發(fā)送給服務(wù)器套接字 */   
  11.         Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);   
  12. /* 接收來自服務(wù)器回射的文本行 */   
  13.         n = Recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);   
  14.    
  15.         recvline[n] = 0;    /* null terminate */   
  16.         Fputs(recvline, stdout);   
  17.     }   
  18. }   
  1.  $./serv &   
  2. [1] 17911   
  3. $ ./client 127.0.0.1   
  4. sending text based on UDP   
  5. sending text based on UDP   
  6. goodbyte..   
  7. goodbyte..   

數(shù)據(jù)報丟失

由于 UDP 是一種不可靠的傳輸協(xié)議。在上面的客戶端 / 服務(wù)器 程序中,若數(shù)據(jù)報在傳輸?shù)倪^程中丟失,那么客戶端就是阻塞于 dg_cli 處理函數(shù)中的 recvfrom 函數(shù)調(diào)用,等待一個永遠(yuǎn)都不會達(dá)到的服務(wù)器應(yīng)答。也有可能是,客戶端數(shù)據(jù)報成功到達(dá)服務(wù)器,但是服務(wù)器的應(yīng)答數(shù)據(jù)報丟失,同樣,客戶端也將永遠(yuǎn)阻塞于 recvfrom 函數(shù)調(diào)用。一般來說,會給客戶端 recvfrom 函數(shù)調(diào)用設(shè)置一個超時時鐘,但是超時時鐘并不能確定是客戶端數(shù)據(jù)報不能到達(dá)服務(wù)器還是服務(wù)器應(yīng)答不能到達(dá)客戶端。所以我們可以采用驗(yàn)證接收到的響應(yīng)。即在 recvfrom 函數(shù)調(diào)用以返回?cái)?shù)據(jù)報發(fā)送者的 IP 地址和端口號,保留來自數(shù)據(jù)報所發(fā)往服務(wù)器的應(yīng)答。

UDP 中使用 connect 函數(shù)

在沒有啟動 UDP 服務(wù)器的情況下,客戶端鍵入文本行之后,并不會回顯該文本行。此時客戶端永遠(yuǎn)阻塞于它的 recvfrom 調(diào)用,等待一個永遠(yuǎn)不會出現(xiàn)的服務(wù)器應(yīng)答。由于服務(wù)器沒有啟動,因此會響應(yīng)一個端口不可到達(dá)的 ICMP 錯誤消息(即異步錯誤),但是該 ICMP 錯誤消息并不會到達(dá)客戶端進(jìn)程,因此客戶端進(jìn)程根本不知道發(fā)生什么,一直阻塞于它的 recvfrom 調(diào)用。為了能使這個異步錯誤到達(dá)客戶端進(jìn)程,我們可以在 UDP 中調(diào)用 connect 函數(shù),使其成為一個已連接的 UDP 套接字,但是該鏈接不會像 TCP 那樣引起三次握手過程。內(nèi)核只是檢查是否存在立即可知的錯誤,并記錄對端的 IP 地址和端口號,然后立即返回到調(diào)用進(jìn)程。

下面要區(qū)分 未連接 UDP 套接字 和 已連接 UDP 套接字:

● 未連接 UDP 套接字:新創(chuàng)建 UDP 套接字默認(rèn)為該情況;

● 已連接 UDP 套接字:對 UDP 套接字調(diào)用 connect 函數(shù)的結(jié)果;

已連接 UDP 套接字 相對于 未連接 UDP 套接字 會有以下的變化:

1、不能給輸出操作指定目的 IP 地址和端口號(因?yàn)檎{(diào)用 connect 函數(shù)時已經(jīng)指定),即不能使用 sendto 函數(shù),而是使用 write 或 send 函數(shù)。寫到已連接 UDP 套接字上的內(nèi)容都會自動發(fā)送到由 connect 指定的協(xié)議地址;

2、不必使用 recvfrom 函數(shù)以獲悉數(shù)據(jù)報的發(fā)送者,而改用 read、recv 或 recvmsg 函數(shù)。在一個已連接 UDP 套接字上,由內(nèi)核為輸入操作返回的數(shù)據(jù)報只有那些來自 connect 函數(shù)所指定的協(xié)議地址的數(shù)據(jù)報。目的地為這個已連接 UDP 套接字的本地協(xié)議地址,發(fā)源地不是該套接字早先 connect 到的協(xié)議地址的數(shù)據(jù)報,不會投遞到該套接字。即只有發(fā)源地的協(xié)議地址與 connect 所指定的地址相匹配才可以把數(shù)據(jù)報傳輸?shù)皆撎捉幼帧_@樣已連接 UDP 套接字只能與一個對端交換數(shù)據(jù)報;

3、由已連接 UDP 套接字引發(fā)的異步錯誤會返回給它們所在的進(jìn)程,而未連接 UDP 套接字不會接收任何異步錯誤;

UDP 客戶端進(jìn)程或服務(wù)器進(jìn)程只在使用自己的 UDP 套接字與確定的唯一對端通信時,才可以調(diào)用 connect 函數(shù)。調(diào)用 connect 函數(shù)的通常是 UDP 客戶端。以下是調(diào)用 connect 函數(shù)的客戶端處理函數(shù):

  1. #include    "unp.h"   
  2.    
  3. void   
  4. dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)   
  5. {   
  6.     int     n;   
  7.     char    sendline[MAXLINE], recvline[MAXLINE + 1];   
  8.    
  9.     Connect(sockfd, (SA *) pservaddr, servlen);   
  10.    
  11.     while (Fgets(sendline, MAXLINE, fp) != NULL) {   
  12.    
  13.         Write(sockfd, sendline, strlen(sendline));   
  14.    
  15.         n = Read(sockfd, recvline, MAXLINE);   
  16.    
  17.         recvline[n] = 0;    /* null terminate */   
  18.         Fputs(recvline, stdout);   
  19.     }   
  20. }   

此時若不啟動服務(wù)器,只啟動客戶端,并鍵入文本行時,客戶端會接收到 異步錯誤。

  1. $ ./client 127.0.0.1   
  2. message...   
  3. read error: Connection refused   

 

責(zé)任編輯:林琳 來源: CSDN博客
相關(guān)推薦

2014-12-11 09:20:30

TCP

2014-12-17 09:22:10

網(wǎng)絡(luò)·安全技術(shù)周刊

2015-03-31 11:24:02

2010-07-06 15:33:10

UDP套接字

2009-03-10 13:59:41

C#套接字編程

2015-05-28 10:47:38

Unix網(wǎng)絡(luò)編程TCP

2021-02-05 15:20:06

網(wǎng)絡(luò)安全套接字命令

2021-03-14 18:22:23

套接字網(wǎng)絡(luò)通信

2012-01-06 13:58:47

JavaTCP

2020-10-15 19:10:05

LinuxAPI函數(shù)

2015-10-16 09:33:26

TCPIP網(wǎng)絡(luò)協(xié)議

2013-12-27 13:39:23

Java套接字

2009-08-21 09:20:44

C#異步套接字

2010-07-05 16:17:18

UDP協(xié)議

2017-01-16 09:26:07

2014-12-03 14:05:01

TCPUDP

2010-06-10 12:42:38

UDP協(xié)議

2010-07-12 11:58:02

Java UDP協(xié)議

2019-06-25 10:32:19

UDP編程通信

2009-08-26 09:48:48

C#異步套接字
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: www成人免费 | 精品国产不卡一区二区三区 | 日本免费在线 | 亚洲一区二区在线视频 | 精品国产乱码久久久久久88av | 台湾佬久久 | 国产一区二区三区四区三区四 | 亚洲一区二区三区在线观看免费 | 国产女人第一次做爰毛片 | 亚洲精品一区二区 | 免费天天干 | 久久国产精品色av免费观看 | 国产精品精品3d动漫 | 激情五月综合 | 草樱av| 中文字幕免费 | 亚洲第一成年免费网站 | 国产91观看 | 中文字幕亚洲一区二区三区 | 日本手机看片 | 最新中文字幕第一页视频 | 国产精品国产精品 | 成人特区| 日本人和亚洲人zjzjhd | 亚洲精品在线免费 | 亚洲天堂av网 | 亚洲va国产日韩欧美精品色婷婷 | 亚洲国产一区二区三区 | 精品一区二区三区在线观看国产 | 亚洲三区在线观看 | 日韩在线电影 | 亚洲高清视频在线观看 | 久久精品这里精品 | 亚洲免费三级 | 国产ts人妖系列高潮 | 天天操天天天 | 成人精品免费视频 | 欧美又大粗又爽又黄大片视频 | 亚洲高清久久 | 日韩精品久久久久 | 久久久www成人免费无遮挡大片 |