1)tftp协议概述
简单文件传输协议,适用于在网络上进行文件传输的一套标准协议,使用UDP传输
特点:
是应用层协议
基于UDP协议实现
数据传输模式:
octet:二进制模式(常用)
mail:已经不再支持
2)tftp下载模型

TFTP通信过程总结
- 服务器在69号端口等待客户端的请求
- 服务器若批准此请求,则使用 临时端口 与客户端进行通信。
- 每个数据包的编号都有变化(从1开始)
- 每个数据包都要得到ACK的确认,如果出现超时,则需要重新发送最后的数据包或ACK包
- 数据长度以512Byte传输的,小于512Byte的数据意味着数据传输结束。
3)tftp协议分析

差错码:
0 未定义,差错错误信息
1 File not found.
2 Access violation.
3 Disk full or allocation exceeded.
4 illegal TFTP operation.
5 Unknown transfer ID.
6 File already exists.
7 No such user.
8 Unsupported option(s) requested.
提取码:6666
客户端代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define ERR_MSG(msg) {\
fprintf(stderr,"line: %d\n",__LINE__);\
perror(msg);\
}
#pragma pack(1)
#define PORT 69
void do_download(int cfd, struct sockaddr_in sin){
socklen_t sinlen = sizeof(sin);
char sendv[128] = "";
unsigned short *type = (unsigned short *)sendv;
*type = htons(1);
char *p = sendv+2;
strcpy(p,"5.png");
char *q = sendv+2+strlen(p)+1;
strcpy(q,"octet");
ssize_t size = 2+strlen(p)+1+strlen(q)+1;
sendto(cfd,sendv,size,0,(struct sockaddr *)&sin,sizeof(sin));
//循环读取,回ACK,当数据钓鱼512时退出循环
ssize_t res = 0;
char recvdata[530] = "";
ssize_t recvsize = 516;
int fd = open("./5.png",O_WRONLY|O_CREAT|O_TRUNC,0664);
if(fd < 0){
ERR_MSG("open");
return ;
}
while(1){
res = recvfrom(cfd,recvdata,recvsize,0,(struct sockaddr *)&sin, &sinlen);
if(res < 0){
ERR_MSG("recvfrom");
return ;
}
else if(res < 516){
write(fd,recvdata+4,res-4);
char ACK[8] = "";
unsigned short *type2 = (unsigned short *)ACK;
*type2 = htons(4);
unsigned short *mid = (unsigned short *)(recvdata+2);
unsigned short *num = (unsigned short *)(ACK+2);
*num = *mid;
sendto(cfd,ACK,4,0,(struct sockaddr *)&sin,sizeof(sin));
break;
}
write(fd,recvdata+4,res-4);
char ACK[8] = "";
unsigned short *type2 = (unsigned short *)ACK;
*type2 = htons(4);
unsigned short *mid = (unsigned short *)(recvdata+2);
unsigned short *num = (unsigned short *)(ACK+2);
*num = *mid;
sendto(cfd,ACK,4,0,(struct sockaddr *)&sin,sizeof(sin));
}
close(fd);
printf("下载完毕\n");
}
void do_upload(int cfd, struct sockaddr_in sin){
//上传
socklen_t sinlen = sizeof(sin);
char upload[128] = "";
unsigned short *type2 = (unsigned short *)upload;
*type2 = htons(2);
char *p2 = upload+2;
strcpy(p2,"girl.png");
char *q2 = upload+2+strlen(p2)+1;
strcpy(q2,"octet");
ssize_t size2 = 2+strlen(p2)+1+strlen(q2)+1;
if(sendto(cfd,upload,size2,0,(struct sockaddr *)&sin,sizeof(sin)) < 0){
ERR_MSG("sendto");
return ;
}
int fd2 = open("./girl.png",O_RDONLY);
if(fd2 < 0){
ERR_MSG("open");
return ;
}
char uploaddata[530] = "";
unsigned short *uploadtype = (unsigned short *)uploaddata;
*uploadtype = htons(3);
unsigned short n = 0;
ssize_t uploadsize = 0;
while(1){
char uploadrecv[4] = "";
recvfrom(cfd,uploadrecv,4,0,(struct sockaddr *)&sin, &sinlen);
if(*(unsigned short *)(uploadrecv+2) == htons(n)){
n ++;
}
//printf("%d %d %d %d\n",uploadrecv[0],uploadrecv[1],uploadrecv[2],uploadrecv[3]);
unsigned short *uploadnums = (unsigned short *)(uploaddata+2);
*uploadnums = htons(n);
uploadsize = read(fd2,uploaddata+4,512);
if(uploadsize < 0){
ERR_MSG("read");
return ;
}
else if(uploadsize < 512){
sendto(cfd,uploaddata,uploadsize+4,0,(struct sockaddr *)&sin,sizeof(sin));
break;
}
sendto(cfd,uploaddata,uploadsize+4,0,(struct sockaddr *)&sin,sizeof(sin));
}
}
int main(int argc, const char *argv[])
{
if(!argv[1]){
printf("请输入ip地址\n");
return -1;
}
int cfd = socket(AF_INET, SOCK_DGRAM, 0);
if(cfd < 0){
ERR_MSG("socket");
return -1;
}
printf("socket create success!\n");
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(argv[1]);
char choose = 0;
while(1){
printf("---------------------\n");
printf("--------1.下载-------\n");
printf("--------2.上传-------\n");
printf("--------3.退出-------\n");
printf("---------------------\n");
printf("请输入>>> ");
choose = getchar();
while(getchar()!=10);
switch(choose){
case '1':
do_download(cfd, sin);
break;
case '2':
do_upload(cfd, sin);
break;
case '3':
goto END;
dafault:
printf("输入错误,请重新输入\n");
break;
}
}
END:
close(cfd);
return 0;
}
注:我把文件定死了,可以根据需求来修改。
本文介绍了TFTP协议,它是一个基于UDP的应用层协议,用于网络上的文件传输。TFTP通信过程中,服务器在69号端口监听,客户端请求并接收数据包,每次512Byte,直到传输结束。文章还提供了一个简单的C语言客户端代码示例,展示了下载和上传文件的过程。
2329

被折叠的 条评论
为什么被折叠?



