一、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; }