UDP(user datagram protocol)用戶數據報協議,屬於傳輸層。
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 }
客戶端

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 }