c语言 模拟tftp——tftp客户端/服务器端仿写

发布于:2022-12-19 ⋅ 阅读:(361) ⋅ 点赞:(0)

TFTP是一个传输文件的简单协议,它基于UDP协议而实现。 此协议设计的时候是进行小文件传输的。 因此它不具备通常的FTP的许多功能,它只能从文件服务器上获得或写入文件,不能列出目录,不进行认证,它传输8位数据。--百度百科

我们平时使用方式如下:可以看到我们使用了put和get加文件名的方式实现了将文件从客户端上传到服务器和从服务器将文件下载到客户端

 以下是对tftp的模拟:

功能实现图

客户端                                                                                          服务器端

我们规定在输入指令以后要加上一个'#'                                        1.监听是否有人链接

发送指令 “put 1.txt#”    上传文件                                                  2.接受链接

"get 1.txt#"                   下载文件                                                  3.接受指令“put 1.txt#”

"quit#"                          退出                                                                            “get 1.txt#”

1.解析空格之前的是命令 char cmd[20]="get"                                      1.解析你recv的字符串            2.解析空格之后#之前      char filename[20]="1.txt"                              2.解析空格之后#之前

3.通过strcmp来判断输入的命令是否正确                                               if(strcmp(cmd,"put"))

if(strcmp(cmd,"put"))                                                                                   1.接收文件大小

1.获得文件的大小        int len ==stat() 12340                                              2.解析12340

2.将文件大小传送过去 "filesize=12340#"                                                3.接受文件内容并保存

3.将文件的内容发送过来                                                              //1.从socket当中读取数据到buf中

        //1.先将文件的内容读取给buf                                                //2.将buf中的数据写到文件中

        //2.将buf通过socket发送过去


1.客户端请求链接

//一.请求链接
int tcp_connect(const char *ip,int port)
{
//创建socket对象(流式套接字TCP)
int socket_fd = socket(AF_INET,SOCK_STREAM,0);//参数是地址组,套接字类型,第三个通常置为0
if(sicket_fd < 0)
{
    perror("socket error");
    return -1;
}
printf("socket success\n");
//设置对方的ip地址和端口号
//定义一个结构体并为其赋值
struct sockaddr_in server;
memset(&server,'\0',sizeof(server));//清空结构体
server.sin_family =AF_INET; //ipv4协议
server.sin_port = htons(port);//端口号
server.sin_addr.s_addr = inet_addr(ip);//网络字节序
//请求链接
if(connect(socket_fd,(struct sockaddr *)&server,sizeof(server))<0)
{
    perror("connect error\n");
    return -1;
}
printf("connect success\n");
return socket_fd;
}

2.服务器端监听

int tcp_socket(const char *ip, int port)
{
    //创建socket
    int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == socket_fd)
    {
        perror("create socket error");
        return -1;
    }
    printf("socket创建成功\n");
 
    //指定端口及ip地址
    struct sockaddr_in server;
    memset(&server,'\0',sizeof(server));
 
    server.sin_family = AF_INET;
    server.sin_port = htons(port);
    server.sin_addr.s_addr = inet_addr(ip);
 
    //绑定ip地址及端口
    if(bind(socket_fd,(struct sockaddr *)&server,sizeof(server)) < 0)
    {
        perror("bind error");
        return -1;
    }
    printf("bind ok\n");
 
    //监听是否有人连接
    if(listen(socket_fd,5) < 0)
    {
        perror("listen error");
        return -1;
    }
    printf("listen ok\n");
 
    return socket_fd;
}


3.客户端操作

int main(int argc, const char *argv[])
{
//入参判断
if(argc<3)
{
    perror("argc error");
    return -1;
}
//连接服务器返回链接后的socket对象
int fd = tcp_connect(argv[1],atoi(argv[2]));//atoi是把字符转成整形
//buf中输入值
char buf[100] = {0};
char cmd[100] = {0};
char filename[100] = {0};
fgets(buf,sizeof(buf),stdin);//键盘键入
send(fd,buf,strlen(buf),0);//发送到服务器
parseStr(buf,cmd,filename);//解析键入的字符串
if(strncmp(cmd,"quit",4)==0)break;
printf("cmd=%s",cmd);
printf("fliename=%s",filename);
DataHandler(fd,cmd,filename);//数据处理(上传下载文件)
//关闭socket
close(fd);
return 0;
}

4.服务器端操作

int main(int argc, const char *argv[])
{
//入参判断
if(argc<3)
{
    perror("argc error");
    return -1;
}
//连接服务器返回链接后的socket对象
int newfd = tcp_tocket(argv[1],atoi(argv[2]));//atoi是把字符转成整形
//buf中输入值
char buf[100] = {0};
char cmd[100] = {0};
char filename[100] = {0};
recv(newfd,buf,sizeof(buf),0);//接收
parseStr(buf,cmd,filename);//解析命令和文件名
if(strncmp(buf,"quit",4)==0)
break;
printf("cmd=%s",cmd);
printf("filename=%s",filename);
DataHandler(newfd,cmd,filename);//数据处理函数
//关闭socket
close(newfd);
return 0;
}

5.解析字符串的函数

//编写一个子函数,根据输入的字符串进行解析命令和文件名
void parseStr(char buf[],char cmd[],char filename[])
{
// 解析命令
int i = 0;
while(buf[i]!='#')
{
    if(buf[i]==' ')
    break;
cmd[i]=buf[i];
i++;
}
cmd[i]='\0';
//解析文件名
if(buf[i]!=' ')//防止有别的符号
return;
i++;//把空格跳过去
int j=0;
while(buf[i+j]!='#')
{
    filename[j]=buf[i+j];
    j++;
}
filename[j]='\0';
}

6.数据处理函数——客户端

int DataHandler(int fd,char * cmd,char * filename)
{
    if(strncmp(cmd,"put",3)==0)
{
    //上传文件
    upload(fd,filename);
}
else if(strncmp(cmd,"get",3)==0)
{
    //下载文件
    download(fd,filename);
}
else
{
    printf("命令有误\n");
}
}


数据处理函数——服务器端

int DataHandler(int fd,char * cmd,char * filename)
{
    if(strncmp(cmd,"get",3)==0)
{
    //下载文件
    download(fd,filename);
}
else if(strncmp(cmd,"get",3)==0)
{
    //上传文件
    upload(fd,filename);
}
else
{
    printf("命令有误\n");
}
}

7.上传下载
 

//上传
int upload(int fd,char * filename)
{
    //获得文件的大小
    struct stat statbuf;
    if(stat(filename,&statbuf)<0)
    {
        perror("stat error");
        return -1;
    }
    printf("filesize=%d\n",statbuf.st_size);
    //2.将文件大小发送过去
    char filesize[20]={'\0'};
    sprintf(filesize,"%d#",statbuf.st_size);
    int n=send(fd,filesize,strlen(filesize),0);
    printf("filesize=%s n=%d\n",filesize,n);
    
    sleep(1);
 
    //以只读方式打开文件
    int fr=open(filename,O_RDONLY);
    if(fr<0)
    {
        perror("open error");
        return -1;
    }
    char bufstr[1024]={'\0'};
    while(1)
    {
        memset(bufstr,'\0',sizeof(bufstr));
        //从文件中读取数据到bufstr
        int n=read(fr,bufstr,sizeof(bufstr));
        if(n==0)
        {
            printf("文件上传成功\n");
            break;
        }
        //将bufstr写入到socket中
        send(fd,bufstr,n,0);
    }
    //关闭文件
    close(fr);
}
//下载
int download(int fd,char * filename)
{
    //接收文件大小
    char buf[20]={'\0'};
    recv(fd,buf,sizeof(buf),0);
    //将字符串转换成整数
    int filesize=atoi(buf);
    printf("filesize=%d\n",filesize);
    //以只写的方式打开文件,文件不存在则新建,文件存在则清空文件中的内容
    int fw=0;
    fw=open(filename,O_WRONLY|O_CREAT|O_TRUNC,0777);
    if(fw<0)
    {
        perror("open error");
        return -1;
    }
    int total = 0;
    char bufstr[1024]={'\0'};
    while(1)
    {
    if(total>=filesize)
    {
        printf("文件保存成功\n");
        break;
    }
    //从socket中读取数据
    int n=recv(fd,bufstr,sizeof(bufstr),0);
    total+=n;
    //将读取到的数据写入到文件中
    write(fw,bufstr,n);
    }
close(fw);
}

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到