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.
一部分下载功能能
#include <head.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PORT 69
#define MAXSIZE 516
int download(int cfd,struct sockaddr_in sin);
int main(int argc, const char *argv[])
{
printf("请输入服务器的IP地址: ");
char ip[15];
scanf("%s",ip);
getchar();
//创建报式套接字
int cfd = socket(AF_INET,SOCK_DGRAM,0);
if(cfd < 0)
{
ERR_MSG("socket");
return -1;
}
// printf("sfd = %d\n",cfd);
//填充服务器自身的地址信息结构体,真是的地址信息结构体根据地址
//AF_INET :man 7 ip
//
//填充服务器的地址信息结构体,给sendto函数使用
//要发给谁就填充谁的地址
struct sockaddr_in sin;
sin.sin_family = AF_INET; //必须填AF_INET
sin.sin_port = htons(PORT); //端口号:服务器绑定的端口号
sin.sin_addr.s_addr = inet_addr(ip); //IP:服务器绑定的IP
//设置允许端口被快速复用
// printf("允许端口快速重用成功\n");
//绑定服务器的地址信息结构体到套接字上--->非必须绑定
//若不绑定,随机端口
download(cfd,sin);
close(cfd);
return 0;
}
int download(int cfd,struct sockaddr_in sin)
{
char buf[MAXSIZE] = "";
char str1[128] = "";
printf("请输入要下载的文件: ");
scanf("%s",str1);
getchar();
//打包数据组
char *ptr = buf;
unsigned short *p1 = (unsigned short*)buf;
*p1 = htons(1);
char *p2 = buf + 2;
strcpy(p2,str1);
char *p3 = p2 + strlen(p2)+1;
strcpy(p3,"octet");
//计算大小
int size =2+strlen(str1)+7;
//发送数据
if(sendto(cfd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin)) < 0)
{
ERR_MSG("sendto");
return -1;
}
int fp = open(str1,O_RDWR|O_CREAT|O_TRUNC,0664);
if(fp < 0)
{
ERR_MSG("open");
return -1;
}
ssize_t res = 0;
//存储接收到的数据包从哪里来
socklen_t addrlen = sizeof(sin);
while(1)
{
//接受数据
bzero(buf,sizeof(buf));
//res = recvfrom(sfd,buf,sizeof(buf),0,NULL,NULL);
res = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&addrlen);
if(res < 0)
{
ERR_MSG("recvfrom");
break;
}
if(write(fp,buf+4,res-4) < 0)
{
ERR_MSG("write");
break;
}
printf("buf[1] = %d res = %ld\n",buf[1],res);
buf[1] = 4;
if(sendto(cfd,buf,4,0,(struct sockaddr*)&sin,sizeof(sin)) < 0)
{
ERR_MSG("sendto");
return -1;
}
if(res<516)
{
printf("文件下载完毕\n");
break;
}
}
//关闭文件描述符
close(cfd);
return -1;
}