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

技術分析:基本 UDP 套接字編程

網絡 網絡管理
UDP 協議和 TCP 協議不同,它是一種面向無連接、不可靠的傳輸層協議。在基于 UDP 套接字編程中,數據傳輸可用函數 sendto 和 recvfrom。

[[124415]]

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

 

 

sendto 與 recvfrom 函數

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

  1. /* 函數功能:發送數據;  
  2.  * 返回值:若成功則返回已發送的字節數,若出錯則返回-1;  
  3.  * 函數原型:  
  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.  * 該函數功能類似于write函數,除了有標識符flags和目的地址信息之外,其他參數一樣;  
  12.  *  
  13.  * flags標識符取值如下:  
  14.  * (1)MSG_DONTROUTE   勿將數據路由出本地網絡  
  15.  * (2)MSG_DONTWAIT    允許非阻塞操作  
  16.  * (3)MSG_EOR         如果協議支持,此為記錄結束  
  17.  * (4)MSG_OOB         如果協議支持,發送帶外數據  
  18.  *  
  19.  * 若sendto成功,則只是表示已將數據無錯誤的發送到網絡,并不能保證正確到達對端;  
  20.  * 該函數通過指定目標地址允許在無連接的套接字之間發送數據(例如UDP套接字);  
  21.  */   
  22.    
  23.  /* 函數功能:接收數據;  
  24.   * 返回值:以字節計數的消息長度,若無可用消息或對方已經按序結束則返回0,若出錯則返回-1;  
  25.   * 函數原型:  
  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.   * 該函數功能與read類似;  
  33.   * 若addr為非空時,它將包含數據發送者的套接字地址;  
  34.   *  
  35.   * flags標識符取值如下:  
  36.   * (1)MSG_WAITALL     等待所有數據可用  
  37.   * (2)MSG_DONTWAIT    允許非阻塞操作  
  38.   * (3)MSG_PEEK        查看已讀取的數據  
  39.   * (4)MSG_OOB         如果協議支持,發送帶外數據  
  40.   */   

基于 UDP 套接字編程

下面我們使用 UDP 協議實現簡單的功能,客戶端從標準輸入讀取數據并把它發送給服務器,服務器接收到數據并把該數據回射給客戶端,然后客戶端收到從服務器回射的數據把它顯示到標準輸出。其功能實現如下圖所示:

 

 

服務器程序

  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.    
  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.     /* 初始化服務器地址信息 */   
  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.     /* 創建套接字,并將服務器地址綁定到該套接字上 */   
  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.     /* 服務器處理函數:讀取套接字文本行,并把它回射給客戶端 */   
  33.     dg_echo(sockfd, (struct sockaddr*) &cliaddr, sizeof(cliaddr));   
  34.    
  35. }   

處理函數

  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. /* 客戶端處理函數:從標準輸入讀入文本行,發送給服務器;接收來自服務器的回射文本,并把它顯示到標準輸出 */   
  32.     dg_cli(stdin, sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));   
  33.    
  34.     exit(0);   
  35. }   

客戶端處理函數

  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. /* 把從標準輸入讀取的文本行發送給服務器套接字 */   
  11.         Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);   
  12. /* 接收來自服務器回射的文本行 */   
  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..   

數據報丟失

由于 UDP 是一種不可靠的傳輸協議。在上面的客戶端 / 服務器 程序中,若數據報在傳輸的過程中丟失,那么客戶端就是阻塞于 dg_cli 處理函數中的 recvfrom 函數調用,等待一個永遠都不會達到的服務器應答。也有可能是,客戶端數據報成功到達服務器,但是服務器的應答數據報丟失,同樣,客戶端也將永遠阻塞于 recvfrom 函數調用。一般來說,會給客戶端 recvfrom 函數調用設置一個超時時鐘,但是超時時鐘并不能確定是客戶端數據報不能到達服務器還是服務器應答不能到達客戶端。所以我們可以采用驗證接收到的響應。即在 recvfrom 函數調用以返回數據報發送者的 IP 地址和端口號,保留來自數據報所發往服務器的應答。

UDP 中使用 connect 函數

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

下面要區分 未連接 UDP 套接字 和 已連接 UDP 套接字:

● 未連接 UDP 套接字:新創建 UDP 套接字默認為該情況;

● 已連接 UDP 套接字:對 UDP 套接字調用 connect 函數的結果;

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

1、不能給輸出操作指定目的 IP 地址和端口號(因為調用 connect 函數時已經指定),即不能使用 sendto 函數,而是使用 write 或 send 函數。寫到已連接 UDP 套接字上的內容都會自動發送到由 connect 指定的協議地址;

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

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

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

  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. }   

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

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

 

責任編輯:林琳 來源: CSDN博客
相關推薦

2014-12-11 09:20:30

TCP

2014-12-17 09:22:10

網絡·安全技術周刊

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網絡編程TCP

2021-02-05 15:20:06

網絡安全套接字命令

2021-03-14 18:22:23

套接字網絡通信

2012-01-06 13:58:47

JavaTCP

2020-10-15 19:10:05

LinuxAPI函數

2015-10-16 09:33:26

TCPIP網絡協議

2013-12-27 13:39:23

Java套接字

2009-08-21 09:20:44

C#異步套接字

2010-07-05 16:17:18

UDP協議

2010-07-12 11:58:02

Java UDP協議

2019-06-25 10:32:19

UDP編程通信

2017-01-16 09:26:07

2009-08-26 09:48:48

C#異步套接字

2014-12-03 14:05:01

TCPUDP

2010-06-10 12:42:38

UDP協議
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品一区在线看 | 天天干天天干 | 在线色网| 在线观看黄色大片 | 激情一区二区三区 | 天天爽一爽| 欧美日韩高清在线观看 | 9久久婷婷国产综合精品性色 | 91视视频在线观看入口直接观看 | 久久久久久av | 中文字幕免费视频 | 91精品国产综合久久久久久漫画 | 久久久久久一区 | 91大神新作在线观看 | 国产欧美精品一区 | 免费观看av | 在线观看中文字幕 | 成人精品国产一区二区4080 | 成人妇女免费播放久久久 | 欧美一级黑人aaaaaaa做受 | 国产精品成人一区二区三区 | 成人福利网站 | 精品一区二区三区在线观看 | 四虎永久免费黄色影片 | 亚洲理论在线观看电影 | 久久首页 | 日韩美av | 国产中文字幕在线 | 中国av在线免费观看 | 欧美一区二区三区四区五区无卡码 | 超碰在线人人 | 国产精品96久久久久久 | 国产精品入口麻豆www | 欧美黄色绿像 | 视频在线一区二区 | 久国产视频| 中文字幕在线播放第一页 | 人人色视频 | jizz视频 | 国产激情综合五月久久 | 99精彩视频 |