• 五十六、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 }

      编译运行测试:

      

  • 相关阅读:
    rails s 命令不起作用
    ubuntu下virtualbox共享usb
    ubuntu15.04 无法识别exfat格式
    .net core 2.2 修改IdentityUser主键标识类型
    Mac os 安装node.js及环境变量的配置过程
    常见互联网网络名词整理
    assert的用法
    Mac系统中 改变 pip总是默认安装在Mac上自带的python上为python3
    测试工程师的发展之路
    MySQL的mysql-8.0.17-winx64版本安装过程中遇到的问题
  • 原文地址:https://www.cnblogs.com/kele-dad/p/10457099.html
Copyright © 2020-2023  润新知