UDP協議 sendto 和 recvfrom 淺析與示例


  UDP(user datagram protocol)用戶數據報協議,屬於傳輸層。

  UDP是面向非連接的協議,它不與對方建立連接,而是直接把數據報發給對方。UDP無需建立類如三次握手的連接,使得通信效率很高。因此UDP適用於一次傳輸數據量很少、對可靠性要求不高的或對實時性要求高的應用場景。

UDP示意圖

  UDP通信的過程如圖所示:

    服務端:

      (1)使用函數socket(),生成套接字文件描述符;

      (2)通過struct sockaddr_in 結構設置服務器地址和監聽端口;

      (3)使用bind() 函數綁定監聽端口,將套接字文件描述符和地址類型變量(struct sockaddr_in )進行綁定;

      (4)接收客戶端的數據,使用recvfrom() 函數接收客戶端的網絡數據;

      (5)向客戶端發送數據,使用sendto() 函數向服務器主機發送數據;

      (6)關閉套接字,使用close() 函數釋放資源;

    客戶端:

      (1)使用socket(),生成套接字文件描述符;

      (2)通過struct sockaddr_in 結構設置服務器地址和監聽端口;

      (3)向服務器發送數據,sendto() ;

      (4)接收服務器的數據,recvfrom() ;

      (5)關閉套接字,close() ;


  (關於 sockaddr sockaddr_in 的區別,可參考:https://blog.csdn.net/qingzhuyuxian/article/details/79736821

 

sendto()

1 1 int sendto(int s, const void *buf, int len, unsigned int flags, 2         const struct sockaddr *to, int tolen);

  返回值說明:

    成功則返回實際傳送出去的字符數,失敗返回-1,錯誤原因會存於errno 中。

  參數說明:

    s:      socket描述符;
    buf:  UDP數據報緩存區(包含待發送數據);
    len:   UDP數據報的長度;
    flags:調用方式標志位(一般設置為0);
    to:  指向接收數據的主機地址信息的結構體(sockaddr_in需類型轉換);
    tolen:to所指結構體的長度;

recvfrom()

1 int recvfrom(int s, void *buf, int len, unsigned int flags, 2           struct sockaddr *from, int *fromlen); 

  返回值說明:

    成功則返回實際接收到的字符數,失敗返回-1,錯誤原因會存於errno 中。

  參數說明:

    s:          socket描述符;
    buf:       UDP數據報緩存區(包含所接收的數據); 
    len:       緩沖區長度。 
    flags:    調用操作方式(一般設置為0)。 
    from:     指向發送數據的客戶端地址信息的結構體(sockaddr_in需類型轉換);
    fromlen:指針,指向from結構體長度值。

 

示例代碼

服務端

 1 #include <unistd.h>
 2 #include <string.h>
 3 #include <stdio.h>
 4 #include <iostream>
 5 #include <netinet/in.h>
 6 #include <sys/socket.h>
 7 #include <sys/types.h>
 8 #include <arpa/inet.h>
 9 
10 #define MAXLINE 4096
11 #define UDPPORT 8001
12 #define SERVERIP "192.168.255.129"
13 
14 using namespace std;
15 
16 int main(){
17     int serverfd;
18     unsigned int server_addr_length, client_addr_length;
19     char recvline[MAXLINE];
20     char sendline[MAXLINE];
21     struct sockaddr_in serveraddr , clientaddr;
22 
23     // 使用函數socket(),生成套接字文件描述符;
24     if( (serverfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ){
25         perror("socket() error");
26         exit(1);
27     }
28 
29     // 通過struct sockaddr_in 結構設置服務器地址和監聽端口;
30     bzero(&serveraddr,sizeof(serveraddr));
31     serveraddr.sin_family = AF_INET;
32     serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
33     serveraddr.sin_port = htons(UDPPORT);
34     server_addr_length = sizeof(serveraddr);
35 
36     // 使用bind() 函數綁定監聽端口,將套接字文件描述符和地址類型變量(struct sockaddr_in )進行綁定;
37     if( bind(serverfd, (struct sockaddr *) &serveraddr, server_addr_length) < 0){
38         perror("bind() error");
39         exit(1); 
40     }
41     
42     // 接收客戶端的數據,使用recvfrom() 函數接收客戶端的網絡數據;
43     client_addr_length = sizeof(sockaddr_in);
44     int recv_length = 0;
45     recv_length = recvfrom(serverfd, recvline, sizeof(recvline), 0, (struct sockaddr *) &clientaddr, &client_addr_length);
46     cout << "recv_length = "<< recv_length <<endl;
47     cout << recvline << endl;
48     
49     // 向客戶端發送數據,使用sendto() 函數向服務器主機發送數據;
50     int send_length = 0;
51     sprintf(sendline, "hello client !");
52     send_length = sendto(serverfd, sendline, sizeof(sendline), 0, (struct sockaddr *) &clientaddr, client_addr_length);
53     if( send_length < 0){
54         perror("sendto() error");
55         exit(1);
56     }
57     cout << "send_length = "<< send_length <<endl;
58     
59     //關閉套接字,使用close() 函數釋放資源;
60     close(serverfd);
61 
62     return 0;
63 }
View Code

 

客戶端

 1 #include <unistd.h>
 2 #include <string.h>
 3 #include <stdio.h>
 4 #include <iostream>
 5 #include <netinet/in.h>
 6 #include <sys/socket.h>
 7 #include <sys/types.h>
 8 #include <arpa/inet.h>
 9 
10 #define MAXLINE 4096
11 #define UDPPORT 8001
12 #define SERVERIP "192.168.255.129"
13 
14 using namespace std;
15 
16 int main(){
17     int confd;
18     unsigned int addr_length;
19     char recvline[MAXLINE];
20     char sendline[MAXLINE];
21     struct sockaddr_in serveraddr;
22 
23     // 使用socket(),生成套接字文件描述符;
24     if( (confd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ){
25         perror("socket() error");
26         exit(1);
27     }
28 
29     //通過struct sockaddr_in 結構設置服務器地址和監聽端口;
30     bzero(&serveraddr, sizeof(serveraddr));
31     serveraddr.sin_family = AF_INET;
32     serveraddr.sin_addr.s_addr = inet_addr(SERVERIP);
33     serveraddr.sin_port = htons(UDPPORT);
34     addr_length = sizeof(serveraddr);
35 
36     // 向服務器發送數據,sendto() ;
37     int send_length = 0;
38     sprintf(sendline,"hello server!");
39     send_length = sendto(confd, sendline, sizeof(sendline), 0, (struct sockaddr *) &serveraddr, addr_length);
40     if(send_length < 0 ){
41         perror("sendto() error");
42         exit(1);
43     }
44     cout << "send_length = " << send_length << endl;
45 
46     // 接收服務器的數據,recvfrom() ;
47     int recv_length = 0;
48     recv_length = recvfrom(confd, recvline, sizeof(recvline), 0, (struct sockaddr *) &serveraddr, &addr_length);
49     cout << "recv_length = " << recv_length <<endl;
50     cout << recvline << endl; 
51 
52     // 關閉套接字,close() ;
53     close(confd);
54 
55     return 0;
56 }
View Code

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM