网络编程(三)UDP TFTP协议

文章目录

一、 UDP

(一)概述

UDP(User Datagram Protocol)用户数据报协议:

是不可靠的无连接的协议。在数据发送前,因为不需要进行连接,所以可以进行高效率的数据传输。

  • 注:
    默认支持并发
    不存在"粘包"的现象

(二)流程


服务器流程

创建套接字--socket()

填充服务器网络信息结构体

将套接字与服务器网络信息结构体绑定--bind()

收发数据--sendto() recvfrom()

关闭套接字--close()

客户端流程

创建套接字--socket()

填充服务器网络信息结构体

收发数据--sendto() recvfrom()

关闭套接字--close()

二、收发函数

(一)recvfrom

c 复制代码
#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);
功能:在套接字上接收一条消息
参数:
    前 4 个参数用法和 recv 函数的4个参数用法一模一样
    后 2 个参数用法和 accept 函数的后两个参数用法一样 用来 保存发送方的网络信息结构体的
返回值:
    成功 实际接收的字节数
    失败 -1 重置错误码
    recvfrom函数用在UDP中是不会返回0的

(二)sendto

c 复制代码
#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);
功能:向套接字上发送一条消息
参数:
    前 4 个参数用法和 send 函数的4个参数用法一模一样
    后 2 个参数用法和 connect 函数的后两个参数用法一样 用来 指定消息发给谁的
返回值:
    成功 实际发送的字节数
    失败 -1 重置错误码

三、实现一个简单的udp服务端和客户端

server.c

c 复制代码
#include <my_head.h>

int main(int argc, char const *argv[])
{
    if(3 != argc){
        printf("Usage: %s IPv4 port\n",argv[0]);
        exit(-1);
    }
    //创建套接字
    int sockfd = 0;
    if(-1 == (sockfd = socket(AF_INET,SOCK_DGRAM,0))){
        ERR_LOG("socket error");
    }
    //填充结构体
    struct sockaddr_in serveraddr;
    serveraddr.sin_family=AF_INET;
    serveraddr.sin_port=htons(atoi(argv[2]));//将命令行第二个参数转成int,并转成网络字节序
    serveraddr.sin_addr.s_addr=inet_addr(argv[1]);
    socklen_t serveraddrlen = sizeof(serveraddr);
    //绑定结构体
    if(-1 == bind(sockfd,(struct sockaddr *)&serveraddr,serveraddrlen)){
        ERR_LOG("bind error");
    }
    //客户信息结构体
    struct sockaddr_in clientaddr;
    socklen_t clientaddrlen = sizeof(clientaddr);
    
    while(1){
        //收发数据
        printf("等待接收数据...\n");
        char buff[128]={0};
        //保存发送方的网络结构体
        if(-1 == recvfrom(sockfd,buff,sizeof(buff),0,(struct sockaddr *)&clientaddr,&clientaddrlen)){
            ERR_LOG("recvfrom error");
        }
        printf("接收到数据[%s]\n",buff);
        strcat(buff,"--zyx");
        //指定发给谁
        if(-1 == sendto(sockfd,buff,sizeof(buff),0,(struct sockaddr *)&clientaddr,clientaddrlen)){
            ERR_LOG("sendto error");
        }
    }

    return 0;
}

client.c

c 复制代码
#include <my_head.h>

int main(int argc, char const *argv[])
{
    if(3 != argc){
        printf("Usage: %s IPv4 port\n",argv[0]);
        exit(-1);
    }
    //创建套接字
    int sockfd = 0;
    if(-1 == (sockfd = socket(AF_INET,SOCK_DGRAM,0))){
        ERR_LOG("socket error");
    }
    //填充结构体
    struct sockaddr_in serveraddr;
    serveraddr.sin_family=AF_INET;
    serveraddr.sin_port=htons(atoi(argv[2]));
    serveraddr.sin_addr.s_addr=inet_addr(argv[1]);
    socklen_t serveraddrlen = sizeof(serveraddr);
    //可以不进行绑定,系统会自动绑定
    //收发数据
    char buff[128];
    while(1){
        printf("请输入数据:");
        scanf("%s",buff);
        if(-1 == sendto(sockfd,buff,sizeof(buff),0,(struct sockaddr *)&serveraddr,serveraddrlen)){
            ERR_LOG("sendto error");
        }
        if(-1 == recvfrom(sockfd,buff,sizeof(buff),0,NULL,NULL)){
            ERR_LOG("recvfrom error");
        }
        printf("应答消息:[%s]\n",buff);
    }
    return 0;
}

四、实现tftp客户端协议

TFTP概述

TFTP:简单文件传送协议

最初用于引导无盘系统,被设计用来传输小文件

特点:

基于UDP协议实现

不进行用户有效性认证

数据传输模式:

octet:二进制模式

netascii:文本模式

mail:已经不再支持

需求分析

1、服务器在69号端口等待客户端的请求

2、服务器若批准此请求,则使用临时端口与客户端进行通信

3、每个数据包的编号都有变化(从1开始)

4、每个数据包都要得到ACK的确认如果出现超时,则需要重新发送最后的包(数据或ACK)

5、数据的长度以512Byte传输

6、小于512Byte的数据意味着传输结束

注意点

1.tftp服务器仅在69号端口接收客户端的请求,批准请求后,使用临时端口 与客户端进行通信

2.每个数据包都要得到ACK的确认

代码实现

c 复制代码
#include <my_head.h>

int main(int argc, char const *argv[])
{
    if(2 != argc){
        printf("Usage: %s IPv4\n",argv[0]);
        exit(-1);
    }
    //创建套接字
    int socketfd = 0;
    if(-1 == (socketfd = socket(AF_INET,SOCK_DGRAM,0))){
        ERR_LOG("socket error");
    }
    //填充结构体
    struct sockaddr_in clentaddr;
    clentaddr.sin_family=AF_INET;
    clentaddr.sin_port=htons(69);
    clentaddr.sin_addr.s_addr=inet_addr(argv[1]); //字符串转四字节网络序整型
    socklen_t clentlen = sizeof(clentaddr);
    
    //发送请求
    char buff[600]={0};
    char filename[20]={0};
    printf("请输入想要下载的文件:");
    scanf("%s",filename);
    int dest_fd = open(filename,O_WRONLY|O_CREAT|O_TRUNC,0664);
    //组装请求数据包
    int nbytes = sprintf(buff,"%c%c%s%c%s%c",0,1,filename,0,"octet",0);
    if(-1 == sendto(socketfd,buff,nbytes,0,(struct sockaddr *)&clentaddr,clentlen)){
        ERR_LOG("sendto error");
    }
    unsigned short option=0;
    unsigned short node =0;
    char data[512]={0};
    char ack[4];
    while(1){
        //接收服务器数据
        memset(buff, 0, sizeof(buff));
        memset(data, 0, sizeof(data));
        nbytes = recvfrom(socketfd,buff,sizeof(buff),0,(struct sockaddr *)&clentaddr,&clentlen);
        //解析数据(网络字节序)
        option = *(unsigned short *)buff;//操作码
        node = *(unsigned short *)(buff+2);//块编号
        strncpy(data,buff+4,nbytes-4);

        if(5 == ntohs(option)){
            //说明出错了
            printf("差错码:%d; 差错信息:%s\n",ntohs(node),buff);
            
        }else if(3 == ntohs(option)){
            printf("已接收到数据\n");
            //说明发送过来数据了,组装应答数据包
            memset(ack,0,4);
            ack[0]=0;
            ack[1]=4;
            *(unsigned short *)(ack+2)=node;
            
            //发送ACK
            if(-1 == sendto(socketfd,ack,4,0,(struct sockaddr *)&clentaddr,clentlen)){
                ERR_LOG("sendto error");
            }
            //写入文件中
            if(-1 == write(dest_fd,data,nbytes-4)){
                ERR_LOG("write error");
            }
        }
        if(nbytes < 516)//数据包内容不足512字节,说明文件拷贝完毕
            break;
    }
    printf("Download over\n");
    close(dest_fd);
    close(socketfd);
    return 0;
}
相关推荐
andxe7 小时前
安科士 AndXe 技术博客:400G QSFP112 SR4 光模块|AI 算力与超算短距互联最优方案
网络·人工智能·光模块·光通信
shiyi.十一8 小时前
第2章:应用层 — 知识要点与架构
网络·计算机网络·架构
DFT计算杂谈9 小时前
无 Root 权限在 Tesla K80 零门槛部署 DeepSeek 大模型
linux·服务器·网络·数据库·机器学习
水境传感 李兆栋9 小时前
GNSS 位移监测站 :毫米级感知,筑牢安全监测防线
网络
sramdram9 小时前
MCU微控制器OA打印机方案
单片机·嵌入式硬件·mcu·mcu微控制器
中微极客10 小时前
2026主流AI Agent框架技术选型与性能对比
运维·网络·人工智能
科芯创展13 小时前
3.5A,60VIN,异步降压芯片,XZ1815
单片机·嵌入式硬件
猿的天空14 小时前
机器人双手迎来全栈训练系统:灵初智能EgoSteer让灵巧手无所不能
网络·人工智能·计算机·ai·程序员·机器人·编程
Xzaveir_77714 小时前
OPPO、vivo、荣耀号码认证:多终端拨测矩阵与异常复现
大数据·网络·科技·矩阵·产品经理·ai-native
wuqingshun31415915 小时前
从网络角度来看,用户从输入网址到网页显示,期间发生了什么?
网络