UDP原来这样理解

目录

什么是UDP

UDP报文头部

实现一个UDP服务器


什么是UDP

UDP(User Datagram Prototocol 用户数据报协议)
1.它是传输层的一个协议
2.它是一个无连接的协议(我们可以理解为发短信,不需要建立连接就可以发送数据)
3.它是一种不可靠传输(因为它面向无连接,所以必然是一种不可靠的传输)
4.面向数据报(可以理解为像冰块一样一块一块发送数据)

UDP报文头部

实现一个UDP服务器

服务器 server.c

int main(int argc, char* argv[])
{
    if(argc != 3)
    {
        printf("Usage: [ipaddr] [port]\n");
        exit(1);
    }
    //创建socket IPV4 UDP 不关心置0
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    //创建addr_in结构体,并初始化
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(argv[2])); 
    //服务器端口号 atoi函数把字符串转换成整型 htons函数把端口号从主机字节序转成网络字节序
    addr.sin_addr.s_addr = inet_addr(argv[1]); 
    //ip地址转换 将一个点分十进制的数转化为二进制  的网络字节序的IPV4地址
    //将服务器ip和端口号进行绑定
    if(bind(sockfd,(struct sockaddr*)&addr,sizeof(addr)) < 0)
    {
        perror("bind");
        exit(2);
    }
    //申请缓存区收发数据
    char buf[1024];
    while(1)
    {
        struct sockaddr_in client; //捕获数据发送源的地址,以便sendto发送
        socklen_t clientLen = sizeof(client);
        //recvfrom()函数:从套接字端口上接收数据,并解析出数据携带的客户端端口地址信息 ,然后放
        //到定义好的client结构体中,
        //参数:sockfd 申请的套接字;buf 收到数据存放的缓存区 ;sizeof(buf)-1 最多存放的大小;
        //0 操作方式,不关心置0; &clien 指向携带有数据源地址信息的缓冲区(指针); &clientLen             //解析过程中clientLen大小可能会发生变化,所以传指针
        ssize_t s = recvfrom(sockfd, buf ,sizeof(buf)-1,0,(struct          sockaddr*)&client,&clientLen);
        if(s > 0)
        {
            buf[s] ='/0';
            //把转化的数据再反转输出
printf("IP:%sPort%d:%s\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port),buf);
            //sendto()函数: 向指定目的地发送数据
            //参数:同上,这里的client为装有发送数据的目的地址缓存区(指针); clientLen目的地址缓存区长度(整型)
            sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&client,clientLen);
        }
    }
    close(sockfd);
    return 0;
}

客户端client.c

int main(int argc,char* argv[])
{
    if(argc != 3)
    {
        printf("Usage: [ipaddr] [port]\n");
        exit(1);
    }
    //创建socket IPV4 UDP 指定协议 不关心置0
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    //创建addr_in结构体并初始化
    struct sockaddr_in client;
    client.sin_family = AF_INET;
    client.sin_port = htons(atoi(argv[2]));
    client.sin_addr.s_addr = inet_addr(argv[1]);
    //建立缓存区,准备向服务器发送数据
    printf("Please Enter : \n");
    char buf[1024];
    while(1)
    {
        printf("#client : ");
        fflush(stdout);
        //从标准输入读数据进buf
        ssize_t s = read(0,buf,sizeof(buf)-1);
        if(s < 0)
        {
            perror("read");
            exit(3);
        }
        buf[s-1] = '\0';
        //sendto()函数: 向指定目的地发送数据
        //参数:sockfd 申请的套接字;buf 收到数据存放的缓存区 ;strlen(buf) 已经写在缓存区的长度;0 操作方式,不关心置0;client为装有发送数据的目的地址缓存区(指针); clientLen目的地址缓存区长度(整型)
        s = sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&client,sizeof(client));
        if(s < 0)
        {
            perror("sendto");
            exit(4);
        }
        //sendto()函数:创建一个接收对端ip&端口信息的addr_in结构体server
        struct sockaddr_in server;
        socklen_t len = sizeof(server);
        //recvfrom()函数:从套接字端口上接收数据,并解析出客户端的端口地址信息 ,然后放到定义好的client结构体中,
        //参数:sockfd 申请的套接字;buf 收到数据存放的缓存区 ;sizeof(buf)-1 最多存放的大小;
0 操作方式,不关心置0; &clien 指向携带有数据源地址信息的缓冲区(指针); &clientLen 解析过程中
clientLen大小可能会发生变化,所以传指针
        s = recvfrom(sockfd,buf,sizeof(buf)-1,0,(struct sockaddr*)&server,&len);
        if(s < 0)
        {
            perror("recvfrom");
            exit(5);
        }
        //
        buf[s] = '/0';
        //把转化的数据再反转输出
        printf("IP : %s , Port : %d %s\n",inet_ntoa(server.sin_addr),ntohs(server.sin_port),buf);
    }
    //关闭
    close(sockfd);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值