UDP服务器和客户端实现

2022-09-17  本文已影响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;
        }
    }

}
上一篇下一篇

猜你喜欢

热点阅读