美文网首页
UDP服务器和客户端实现

UDP服务器和客户端实现

作者: 二进制人类 | 来源:发表于2022-09-17 20:04 被阅读0次

    C/S 架构流程

    截图.png

    相关API

    创建socket

    #include <sys/types.h>          
    #include <sys/socket.h>
    int socket(int domain, int type, int protocol);
    /*
    参数:
        参数1:domain表示通信域
            AF_UNIX, AF_LOCAL   Local communication              unix(7)    本地域
            AF_INET             IPv4 Internet protocols          ip(7)      IPV4地址协议族 
            AF_INET6            IPv6 Internet protocols          ipv6(7)     IPV4地址协议族 
        参数2:type表示通信节点的通信方式
            SOCK_STREAM       流式套接字类型    TCP    数据通信方式是以字节流形式传输
            SOCK_DGRAM        数据报套接字类型  UDP    数据通信方式是以数据包形式传输
            SOCK_RAW          原始套接字               可以对底层协议进行修改和访问
        参数3:protocol使用的协议号,在SOCK_RAW的时候修改,在默认情况下使用0;
    返回值:成功返回通信节点文件描述符,失败返回-1且修改errno的值。
     */
    

    设置主机的IP地址和端口

    #include <sys/types.h>         
    #include <sys/socket.h>
    
    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
     /* 
    参数:
        参数1:sockfd表示创建成功的套接字文件描述符;
        参数2:addr指针,指向的空间用来存储主机的IP和当前进程的端口号。
           通用地址结构
            struct sockaddr {
                sa_family_t sa_family;         表示采用地址协议族 
                char        sa_data[14];       存储主机的IP地址和当前进程的端口号:
                                                    1) IP地址和端口号的存储顺序不确定;
                                                    2) 在存储的时候是采用主机字节序还是网络                                                 字节序也不确定;
                                                    导致在构造结构体成员值的时候会比较麻烦,                                                 很容易出错。
                                              
            };
            专用地址结构实现:根据套接字的通信来查看man手册(AF_INET:man 7 ip)) 
            struct sockaddr_in {
                sa_family_t    sin_family;  协议 AF_INET ipv4 AF_INET6 ipv6
                in_port_t      sin_port;   端口
                struct in_addr sin_addr;  网络地址结构体
            };
    
        
            struct in_addr {
                uint32_t       s_addr;          如果IP地址指定,只能绑定给定的IP地址;
                                                如果使用INADDR_ANY,此时自动绑定主机中所有网                                             卡的IP地址              
            };
        参数3:表示参数2指针指向空间的大小。
    返回值:
        成功返回0,失败返回-1且修改errno的值。
            
            */
    

    接收数据

    #include <sys/types.h>
    #include <sys/socket.h>
    ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
    /*
    参数:
        参数1:sockfd套接字文件描述符;
        参数2:buf指针指向的空间用存储接收到的数据;
        参数3:len表示参数2指向空间的大小;
        参数4:flags表示数据接收的方式,常用0表示阻塞接收。
        参数5:src_addr指向的空间用来返回对端的IP地址和端口号,如果不关心则使用NULL;
        参数6:addrlen指针指向的空间用来返回参数5指向对端空间的大小。
    返回值:
        成功返回接收数据的字节数,失败返回-1且修改errno的值
    */
    

    发送数据

    #include <sys/types.h>
    #include <sys/socket.h>
    ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
    /*
    参数:
        参数1:socket套件文件描述符;
        参数2:buf指向的空间存储的是需要发送的数据;
        参数3:len表示参数2指向空间的大小;
        参数4:flags表示数据发送的方式,一般使用0表示阻塞发送
        参数5:dest_addr指针指向的结构体空间存储的是目的主机的IP地址和端口号;
        参数6:addrlen表示参数5指向空间的大小;
    返回值:
        成功返回发送成功的字节数,失败返回-1且修改errno的值
    */
    

    实例

    服务器实例

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    
    int main()
    {
        int sockfd;
        int ret;
        struct sockaddr_in srvaddr;
        struct sockaddr_in cltaddr;
        socklen_t addrlen = sizeof(cltaddr);
        char buf[128];
    
        /* 创建数据报套接字文件 */
        sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (sockfd == -1)
        {
            perror("socket");
            return -1;
        }
    
        /* 初始化服务器地址空间结构体 */
        srvaddr.sin_family = AF_INET;
        srvaddr.sin_port = htons(8888);
        srvaddr.sin_addr.s_addr = inet_addr("192.168.1.130");
        /* 设置服务器的IP地址和端口号 */
        ret = bind(sockfd, (const struct sockaddr *)&srvaddr, sizeof(srvaddr));
        if (ret == -1)
        {
            perror("bind");
            return -1;
        }
        printf("init UDP server sucess\n");
    
        while(1)
        {
            /* 接收数据 */
            ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&cltaddr, &addrlen);
            if (ret == -1)
            {
                perror("recvfrom");
                return -1;
            }
            printf("buf : %s\n", buf);
    
            /* 发送数据 */
        }
    }
    

    客户端实现

    #include <stdio.h>
    #include <sys/types.h>         
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    
    int main()
    {
        int sockfd;
        int ret;
        struct sockaddr_in srvaddr;
        char buf[128];
    
        /* 创建数据报套接字文件 */
        sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (sockfd == -1)
        {
            perror("socket");
            return -1;
        }
    
        /* 初始化接收主机地址空间结构体 */
        srvaddr.sin_family = AF_INET;
        srvaddr.sin_port = htons(8888);
        srvaddr.sin_addr.s_addr = inet_addr("192.168.1.130");
    
        while(1)
        {
            fgets(buf, sizeof(buf), stdin);
            /*发送数据*/
            ret = sendto(sockfd, buf, sizeof(buf), 0, (const struct sockaddr *)&srvaddr, sizeof(srvaddr));
            if (ret == -1)
            {
                perror("sendto");
                return -1;
            }
        }
    
    }
    

    相关文章

      网友评论

          本文标题:UDP服务器和客户端实现

          本文链接:https://www.haomeiwen.com/subject/khpeortx.html