一、tftp简介
TFTP:简单文件传送协议,最初用于引导无盘系统,被设计用来传输小文件
特点:
基于UDP协议实现
不进行用户有效性认证
数据传输模式:
octet:二进制模式
netascii:文本模式
mail:已经不再支持
二、TFTP通信过程
1、服务器在69号端口等待客户端的请求
2、服务器若批准此请求,则使用临时端口与客户端进行通信
3、每个数据包的编号都有变化(从1开始)
4、每个数据包都要得到ACK的确认如果出现超时,则需要重新发送最后的包(数据或ACK)
5、数据的长度以512Byte传输
6、小于512Byte的数据意味着传输结束
三、协议分析
3.错误码
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 <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
if(argc!=3){
printf("./a.out server_ip file_name\n");
return 0;
}
//创建socket套接字(基于UDP)
int socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
if(socket_fd<0){
perror("socket");
return 0;
}
//组tftp文件读取请求
unsigned char cmd[128]="";
int len = sprintf(cmd,"%c%c%s%c%s%c",0x00,0x01,argv[2],0,"octet",0);
//将请求cmd发送到服务器69端口
struct sockaddr_in server;
bzero(&server,sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(69);
inet_pton(AF_INET,argv[1],&server.sin_addr.s_addr);
sendto(socket_fd,cmd,len,0,(struct sockaddr *)&server,sizeof(server));
//打开一个本地空文件,将得到的数据写进去
int fd=open(argv[2],O_WRONLY | O_CREAT,0666);
if(fd<0){
perror("open");
return 0;
}
//不停读取服务器传过来的文件数据
unsigned short num=0;
while(1){
unsigned char buf[1024]="";
struct sockaddr_in from;
socklen_t from_len = sizeof(from);
int len = recvfrom(socket_fd,buf,sizeof(buf),0,(struct sockaddr *)&from, &from_len);
//判断收到的数据的操作码(必须是00 03表示文件数据)
if(buf[1]==0x03){
//将文件数据写入本地文件中
//防止写入重复数据
if((num+1) == ntohs(*(unsigned short *)(buf+2)))
{
write(fd,buf+4,len-4);
num = ntohs(*(unsigned short *)(buf+2));
printf("recv:%d\n",num);
}
//给服务器发送ACK回应
buf[1]=4;
sendto(socket_fd,buf,4,0,(struct sockaddr *)&from,sizeof(from));
if(len<516){
//最后一个文件数据
break;
}
}
}
//关闭套接字
close(socket_fd);
//关闭文件
close(fd);
return 0;
}