五十六、linux 编程——UDP 编程模型

56.1 UDP 编程模型

56.1.1 编程模型

  UDP 协议称为用户数据报文协议,可靠性比 TCP 低,但执行效率高

  

56.1.2 API

(1)发送数据

  

  • 函数参数:
    • sockfs:套接字文件描述符
    • buf:发送的数据
    • len:发送的数据的大小,即多少个字节
    • flags:一般设置为0
    • dest_addr:接收方的地址
    • addrlen:前面地址结构体 dest_addr 的大小
    • msg:将发送的数据封装在 msghdr 的结构体中
  • 返回值:返回值都一样,成功,则返回发送的字节数;出错,则返回-1

  

(2)接收数据

  

  • 返回值:返回消息的字节数,无消息,返回0;出错返回 -1

56.2 例子

56.2.1 服务器编程

  time_udp_server.c

  1 #include <sys/types.h>
  2 #include <sys/socket.h>
  3 #include <arpa/inet.h>
  4 #include <unistd.h>
  5 #include <netdb.h>
  6 #include <stdio.h>
  7 #include <stdlib.h>
  8 #include <signal.h>
  9 #include <string.h>
 10 #include <time.h>
 11 
 12 int sockfd;
 13 
 14 void sig_handler(int signo)
 15 {
 16     if(signo == SIGINT){
 17         printf("server close
");
 18         close(sockfd);
 19         exit(1);
 20     }
 21 }
 22 
 23 void out_addr(struct sockaddr_in *clientaddr)
 24 {
 25     char ip[16];
 26     int port;
 27     memset(ip, 0, sizeof(ip));
 28     inet_ntop(AF_INET, &clientaddr->sin_addr.s_addr, ip, sizeof(ip));
 29     port = ntohs(clientaddr->sin_port);
 30     printf("client: %s(%d)
", ip, port);
 31 }
 32 
 33 /** 和客户端进行通信 */
 34 void do_service(int fd)
 35 {
 36     struct sockaddr_in clientaddr;
 37     socklen_t len = sizeof(clientaddr);
 38     char buffer[1024];
 39     memset(buffer, 0, sizeof(buffer));
 40     /** 接收客户端的数据报文 */
 41     if(recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&clientaddr, &len) < 0){
 42         perror("recvfrom error");
 43     }
 44     else{
 45         out_addr(&clientaddr);
 46         printf("client send into: %s
", buffer);
 47 
 48         /** 向客户端发送数据报文 */
 49         long int t = time(0);
 50         char *ptr = ctime(&t);
 51         ssize_t size = strlen(ptr) * sizeof(char);
 52         if(sendto(sockfd, ptr, size, 0, (struct sockaddr *)&clientaddr, len) < 0){
 53             perror("sendto error");
 54         }
 55     }
 56 
 57 }
 58 
 59 int main(int argc, char *argv[])
 60 {
 61     if(argc < 2){
 62         printf("usage: %s port
", argv[0]);
 63         exit(1);
 64     }
 65 
 66     if(signal(SIGINT, sig_handler) == SIG_ERR){
 67         perror("signal sigint error");
 68         exit(1);
 69     }
 70 
 71     /** 步骤1: 创建 socket */
 72     sockfd = socket(AF_INET, SOCK_DGRAM, 0);
 73     if(sockfd < 0){
 74         perror("socket error");
 75         exit(1);
 76     }
 77 
 78     int ret;
 79     int opt = 1;
 80     /** 设置套接字选项, 让停掉的端口马上可以使用 */
 81     if((ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) < 0){
 82         perror("setsockopt error");
 83         exit(1);
 84     }
 85 
 86     /** 步骤2: 调用 bind 函数对 socket 和地址进行绑定 */
 87     struct sockaddr_in serveraddr;
 88     memset(&serveraddr, 0, sizeof(serveraddr));
 89     serveraddr.sin_family = AF_INET; ///< ipv4
 90     serveraddr.sin_port = htons(atoi(argv[1])); ///< port
 91     serveraddr.sin_addr.s_addr = INADDR_ANY; ///<IP
 92     if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0){
 93         perror("bind error");
 94         exit(1);
 95     }
 96 
 97     /** 步骤3: 和客户端进行双向的数据通信 */
 98     while(1){
 99         do_service(sockfd);
100     }
101 
102     return 0;
103 }

56.2.2 客户端编程

  time_udp_client.c

 1 #include <sys/types.h>
 2 #include <sys/socket.h>
 3 #include <arpa/inet.h>
 4 #include <unistd.h>
 5 #include <netdb.h>
 6 #include <stdio.h>
 7 #include <stdlib.h>
 8 #include <signal.h>
 9 #include <string.h>
10 #include <time.h>
11 
12 int main(int argc, char *argv[])
13 {
14     if(argc < 3){
15         printf("usage: %s ip port
", argv[0]);
16         exit(1);
17     }
18 
19     /** 步骤1: 创建 socket */
20     int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
21     if(sockfd < 0){
22         perror("socket error");
23         exit(1);
24     }
25 
26     /** 步骤2: 调用 recvfrom 和 sendto 等函数和服务器端双向通信 */
27     struct sockaddr_in serveraddr;
28     memset(&serveraddr, 0, sizeof(serveraddr));
29     serveraddr.sin_family = AF_INET; ///< ipv4
30     serveraddr.sin_port = htons(atoi(argv[2])); ///< port
31     inet_pton(AF_INET, argv[1], &serveraddr.sin_addr.s_addr);
32     char buffer[1024] = "hello world";
33     /** 向服务器端发送数据报文 */
34     if(sendto(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0){
35         perror("sendto error");
36         exit(1);
37     }
38     else{
39         /** 接受服务器端发送的数据报文 */
40         memset(buffer, 0, sizeof(buffer));
41         if(recv(sockfd, buffer, sizeof(buffer), 0) < 0){
42             perror("recv error");
43             exit(1);
44         }
45         else{
46             printf("%s", buffer);
47         }
48     }
49 
50     close(sockfd);
51 
52     return 0;
53 }

  编译运行测试:

  

原文地址:https://www.cnblogs.com/kele-dad/p/10457099.html