zoukankan      html  css  js  c++  java
  • 3.UDP通信

    1.UDP协议的特点:

      不需要链接, 不可靠传输协议,速度快实时性强,传输数据量小。

    2.发送数据端实现的步骤如下:

      1. 创建套接字(socket)  SOCK_STREAM--TCP,  SOCK_DGRAM--UDP

      2. 发送数据(sendto)

    3.接收数据端的实现步骤如下:

    1. 创建套接字(socket)
    2. 绑定端口地址(bind)
    3. 接收数据(recvfrom)阻塞

      Linux提供的函数接口如下:

    发送数据

    ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                          const struct sockaddr *dest_addr, socklen_t addrlen);
    参数:int sockfd套接字描述符, 
          const void *buf,--要发送的数据
          size_t len数据长度
          int flags-标志设置为0
          const struct sockaddr *dest_addr----数据要发送到的地址, 
      socklen_t addrlen---dest_addr长度
    返回值:成功发送的字节数, 失败-1

    接收数据

    ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                            struct sockaddr *src_addr, socklen_t *addrlen);
    
    参数:int sockfd套接字描述符, 
          const void *buf,--要存储接收的数据
          size_t len数据长度--buf空间大小
      socklen_t addrlen---dest_addr长度//地址长度
          int flags-标志设置为0
          struct sockaddr *src_addr;---存储发送方的地址端口
          socklen_t *addrlen----src_addr指针所指向的空间大小
    
    返回值:成功发送的字节数, 失败-1

    发送端的实现代码如下:

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/socket.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    //#include <       
    #include <netinet/in.h>
    #include <arpa/inet.h>
    
    int main(void)
    {
        //1.创建套接字
        int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if(sockfd < 0)
        {
            perror("socket fail");
            exit(1);
        }
        //2.发送数据到指定的地址端口
        char buffer[128]="hello world";
        struct sockaddr_in toaddr;
        memset(&toaddr, 0, sizeof(toaddr));
        toaddr.sin_family = AF_INET;
        toaddr.sin_port = htons(6666);
        toaddr.sin_addr.s_addr = inet_addr("192.168.1.240");
    
        size_t size = sendto(sockfd, buffer, strlen(buffer),0, 
                (struct sockaddr*)&toaddr, sizeof(toaddr));
        if(size  != strlen(buffer) )
        {
            perror("sendto fail");
            exit(1);
        }
    
        return 0;
    }

    接收端的实现代码如下:

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/socket.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    //#include <       
    #include <netinet/in.h>
    #include <arpa/inet.h>
    
    int main(void)
    {
        //1.创建套接字
        int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if(sockfd < 0)
        {
            perror("socket fail");
            exit(1);
        }
    
        //2.绑定
        struct sockaddr_in toaddr;
        memset(&toaddr, 0, sizeof(toaddr));
        toaddr.sin_family = AF_INET;
        toaddr.sin_port = htons(6666);
        toaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        int ret  = bind(sockfd, (struct sockaddr*)&toaddr, sizeof(toaddr));
        if(ret < 0)
        {
            perror("bind fail");
            exit(1);
        }
    
        
        //3.接收数据
        char buffer[128]={0};
        struct sockaddr_in saddr;
        socklen_t len = sizeof(saddr);
        size_t size = recvfrom(sockfd, buffer, sizeof(buffer),0, 
                (struct sockaddr*)&saddr,&len);
        if(size  < 0 )
        {
            perror("recvfrom fail");
            exit(1);
        }
        printf("%s
    ", buffer);
        return 0;
    }

    2.套接字的设置  setsockopt

    int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
    参数:int sockfd --要设置的套接字
          int level --设置级别选择(SOL_SOCKET, IPPROTO_IP)
          int optname --要与第二参数对应
          const void *optval --根据第三个参数后面的数据类型
    socklen_t optlen---第四个参数的空间的大小
    返回值:成功0, 失败-1

    3.设置端口复用  只有最后绑定端口的那个基础讷航才可以接收到端口的数据

    int op = 1;
        int opt = setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &op, sizeof(op));
        if(opt < 0)
        {
            perror("setsockopt fail");
            exit(1);
        }

    4.UDP实现广播通信

     步骤如下:

      在linux首先要通过setsockopt来开启关闭广播(发送端)

    int op = 1;
        int opt = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &op, sizeof(op));

      发送广播的流程:

        (1)创建套接字(SOCK_DGRAM

        (2)开启广播

        (3)发送数据到广播地址(假设是192.168.1.255)

    #include <sys/socket.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>    
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #define BROADCAST_ADDR "192.168.1.255"
    #define PORT 6666
    int main(void)
    {
        //1.创建套接字
        int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if(sockfd < 0)
        {
            perror("socket fail");
            exit(1);
        }
        //开启广播
        int op =1;
        int ret  = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST,&op, sizeof(op));
        if(ret < 0)
        {
            perror("开启广播失败");
            exit(1);
        }
        //2.发送数据到指定的地址端口
        char buffer[128]="hello world";
        struct sockaddr_in toaddr;
        memset(&toaddr, 0, sizeof(toaddr));
        toaddr.sin_family = AF_INET;
        toaddr.sin_port = htons(PORT);
        toaddr.sin_addr.s_addr = inet_addr(BROADCAST_ADDR);
    
        size_t size = sendto(sockfd, buffer, strlen(buffer),0, 
                (struct sockaddr*)&toaddr, sizeof(toaddr));
        if(size  != strlen(buffer) )
        {
            perror("sendto fail");
            exit(1);
        }
        return 0;
    }

        数据接收端:

        (4)创建套接字(socket)

        (5)绑定端口地址(bind)

        (6)接收数据(recvfrom)阻塞

    5.UDP实现组播

      组播(多播):只有超级用户才有权限发送组播信息  组播地址 224.0.0.0---239.255.255.255

    实现步骤:

      发送端:

        (1)     创建udp套接字

        (2)     发送数据到组播地址

      接收端

        (1)     创建udp套接字

        (2)     绑定地址端口

        (3)     加入组播/ 退出组播

          要通过setsockopt设置套接字添加到组播组

    struct ip_mreq  {                                                           
         struct in_addr imr_multiaddr;   /* IP multicast address of group */组播地址
         struct in_addr imr_interface;   /* local IP address of interface */本地网卡
    } mreq; 
    初始化mreq
    mreq.imr_multiaddr = 
    setsockopt(sockfd, IPPROTO_IP,  IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));

        (4)     接收数据

    例子:添加组播数组
    
    struct ip_mreq  mreq;
        mreq.imr_multiaddr.s_addr = inet_addr("224.0.0.100");
        mreq.imr_interface.s_addr = htonl(INADDR_ANY);
        ret = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));

    UDP组播发送端的代码如下:

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/socket.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    //#include <       
    #include <netinet/in.h>
    #include <arpa/inet.h>
    
    int main(void)
    {
        //1.创建套接字
        int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if(sockfd < 0)
        {
            perror("socket fail");
            exit(1);
        }
        //2.发送数据到指定的地址端口
        char buffer[128]="hello world";
        struct sockaddr_in toaddr;
        memset(&toaddr, 0, sizeof(toaddr));
        toaddr.sin_family = AF_INET;
        toaddr.sin_port = htons(6666);
        toaddr.sin_addr.s_addr = inet_addr("224.0.0.100");
    
        size_t size = sendto(sockfd, buffer, strlen(buffer),0, 
                (struct sockaddr*)&toaddr, sizeof(toaddr));
        if(size  != strlen(buffer) )
        {
            perror("sendto fail");
            exit(1);
        }
    
        return 0;
    }

    接收端的代码如下:

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/socket.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    //#include <       
    #include <netinet/in.h>
    #include <arpa/inet.h>
    
    int main(void)
    {
        //1.创建套接字
        int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if(sockfd < 0)
        {
            perror("socket fail");
            exit(1);
        }
    
        //设置端口复用
        int op = 1;
        int opt = setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &op, sizeof(op));
        if(opt < 0)
        {
            perror("setsockopt fail");
            exit(1);
        }
    
    
        //2.绑定
        struct sockaddr_in toaddr;
        memset(&toaddr, 0, sizeof(toaddr));
        toaddr.sin_family = AF_INET;
        toaddr.sin_port = htons(6666);
        toaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        int ret  = bind(sockfd, (struct sockaddr*)&toaddr, sizeof(toaddr));
        if(ret < 0)
        {
            perror("bind fail");
            exit(1);
        }
    
        
        //加入到组播组
        //struct sockaddr_in s;
        //s.sin_addr.s_addr = inet_addr("192.168.1.51";)
    
    
        struct ip_mreq  mreq;
        mreq.imr_multiaddr.s_addr = inet_addr("224.0.0.100");
        mreq.imr_interface.s_addr = htonl(INADDR_ANY);
        ret = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
    
        //3.接收数据
        char buffer[128]={0};
        struct sockaddr_in saddr;
        socklen_t len = sizeof(saddr);
        size_t size = recvfrom(sockfd, buffer, sizeof(buffer),0, 
                (struct sockaddr*)&saddr,&len);
        if(size  < 0 )
        {
            perror("recvfrom fail");
            exit(1);
        }
    
        printf("%s
    ", buffer);
    
        return 0;
    }

    PS:哪里写错了请指正,互相学习。

  • 相关阅读:
    XidianOJ 1099 A simple problem
    XidianOJ 1097 焊板子的xry111
    XidianOJ 1172 Hiking
    XidianOJ 1176 ship
    bzoj1912(树的直径)
    黑暗城堡(最短路径树)
    poj1639(k限制最小生成树)
    0-1分数规划
    tyvj1391(Kruskal)
    [Usaco2007 Nov]Cow Relays(矩阵乘法+floyd)
  • 原文地址:https://www.cnblogs.com/smallqizhang/p/12564471.html
Copyright © 2011-2022 走看看