菜鸟笔记
提升您的技术认知

TFTP协议(基于UDP)

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


}