一、TFTP概述
TFTP是一个传输文件的简单协议,通常使用UDP协议而实现,它只能从文件服务器上获得或写入文件,不能列出目录,不进行认证,它传输8位数据。传输中有三种模式:netascii,这是8位的ASCII码形式,另一种是octet,这是8位源数据类型;最后一种mail已经不再支持,它将返回的数据直接返回给用户而不是保存为文件。任何传输起自一个读取或写入文件的请求,这个请求也是连接请求。如果服务器批准此请求,则服务器打开连接,数据以定长512字节传输。每个数据包包括一块数据,服务器发出下一个数据包以前必须得到客户对上一个数据包的确认。如果一个数据包的大小小于512字节,则表示传输结束。如果数据包在传输过程中丢失,发出方会在超时后重新传输最后一个未被确认的数据包。通信的双方都是数据的发出者与接收者,一方传输数据接收应答,另一方发出应答接收数据。
二、TFTP通信过程
1、服务器在69号端口等待客户端的请求
2、服务器若批准此请求,则使用临时端口与客户端进行通信
3、每个数据包的编号都有变化(从1开始)
4、每个数据包都要得到ACK的确认如果出现超时,则需要重新发送最后的包(数据或ACK)
5、数据的长度以512Byte传输
6、 小于512Byte的数据意味着传输结束
三、TFTP协议
操作码:1 — 读请求
2 — 写请求
3 — 数据报
4 — 数据确认
5 — 错误信息
6 — 选项确认
注意:上面的 0 代表的是 '\0'。
四、ubuntu12.04 配置 TFTP
1、安装TFTP软件
sudo apt-get install tftp-hpa tftpd-hpa
注意:tftp-hpa是客户端,tftpd-hpa是服务器端
2、建立tftpboot 目录,作为服务器的目录
sudo mkdir ~/tftpboot
注意:释放权限:(服务器目录,需要设置权限为 777,chomd 777)
sudo chmod 777 ~/tftpboot
3、配置TFTP服务器
sudo gedit /etc/default/tftpd-hpa
将原来的内容
修改为
4、重新启动TFTP服务
sudo service tftpd-hpa restart
5、测试
$ cd ~/tftpboot
$ echo "hello tftp service" >> a.txt
$ cd ~
$ echo "hello tftp service, put to tftp service" >> b.txt
$ tftp localhost
tftp> get a.txt
tftp> put b.txt
注意:其中get是获取文件,put是将文件上传到TFTP服务器上。
五、TFTP上传下载程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
unsigned short port=69;
char filename[20]="";
char type[10]="";
char req_cmd[512]="";
char *server_ip=NULL;
int fd;
int sockfd;
if(argc!=2)
{
printf("\e[31m%s%s\e[0m\n","Cmd error!\n","Please input server IP");
exit(-1);
}
server_ip=argv[1];
sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(sockfd<0)
{
perror("socket");
exit(-1);
}
struct sockaddr_in server_addr;
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(port);
inet_pton(AF_INET,server_ip,&server_addr.sin_addr);
socklen_t addr_len=sizeof(server_addr);
printf("\e[31m%s\e[0m","Please input Type(write or read):");
scanf("%s",type);
printf("\e[31m%s\e[0m","Please input filename:");
scanf("%s",filename);
if(!strcmp(type,"read"))
{
if((fd=open(filename,O_WRONLY|O_CREAT,0755))==-1)
{
perror("open");
exit(-1);
}
int ret=sprintf(req_cmd,"%c%c%s%c%s%c",0,1,filename,0,"octet",0);
sendto(sockfd,req_cmd,ret,0,(struct sockaddr *)&server_addr,sizeof(server_addr));
while(1)
{
char buf[1024]="";
int ret=recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&server_addr,&addr_len);
if(buf[1]==3)
{
char ack_cmd[20]="";
write(fd,buf+4,ret-4);
int ack_ret=sprintf(ack_cmd,"%c%c%c%c",0,4,buf[2],buf[3]);
sendto(sockfd,ack_cmd,ack_ret,0,(struct sockaddr *)&server_addr,sizeof(server_addr));
}
if(ret<516)
{
close(fd);
break;
}
}
}
else if(!strcmp(type,"write"))
{
if((fd=open(filename,O_RDONLY))==-1)
{
perror("open");
exit(-1);
}
int ret_cmd=sprintf(req_cmd,"%c%c%s%c%s%c",0,2,filename,0,"octet",0);
sendto(sockfd,req_cmd,ret_cmd,0,(struct sockaddr *)&server_addr,sizeof(server_addr));
while(1)
{
char buf[516]="";
static int num=0;
num++;
recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&server_addr,&addr_len);
buf[1]=3;
buf[2]=num/256;
buf[3]=num%256;
int ret=read(fd,buf+4,sizeof(buf)-4);
if(ret==0)
{
close(fd);
break;
}
sendto(sockfd,buf,ret+4,0,(struct sockaddr *)&server_addr,sizeof(server_addr));
}
}
close(sockfd);
return 0;
}