UDP编程——TFPT(小文件传输)

一、TFTP概念

1.1、TFTP:简单文件传送协议

            最初用于引导无盘系统,被设计用来传输小文件

特点:
          基于UDP协议实现
          不进行用户有效性认证

数据传输模式:
                        octet:二进制模式(常用)
                        netascii:文本模式
                         mail:已经不再支持

二、TFTP通信过程

2.1、  TFTP通信过程总结

1、服务器在69号端口等待客户端的请求
2、服务器若批准此请求,则使用临时端口与客户端进行通信
3、每个数据包的编号都有变化(从1开始)
4、每个数据包都要得到ACK的确认如果出现超时,则需要重新发送最后的包(数据或
ACK)
5、数据的长度以512Byte传输
6、小于512Byte的数据意味着传输结束

 2.2、TFTP协议分析

 2.2.1、分析读写请求

 2.2.2、分析数据包

 2.2.3、分析ACK(应答)

   操作码为04,块编号为刚接收的号码:01

   如0401,表示接收成功,并且数据无误

2.2.4、ERROR(数据丢失应答)

    操作码为05,如果接收到数据有误,回复05,即可让服务器在次重新发送。

不同的差错码 ,有不同的信息

    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.

三、编写代码流程(客户端)

第一步:创建 套接字——socket函数

第二步:补齐sockaddr_in  信息(发给谁)

第三步;创建一个子函数{   do_download(int sockfdstruct  sockaddr_in  mysockaddr)}

下面的代码都在子函数下创建

第四步:把读写请求设置好写进一个ask_buf数组里,比如:下载huai.txt文件:

          sprintf(ask_buf, "%c%c%s%c%s%c", 0, 1, huai.txt, 0, "octet", 0);

第五步:把ask_buf发送给服务器——sendto函数

第六步:接收到 服务器发来的信息(有数据包,有对方的ip,端口号)——recvfrom函数

第七步:拆解数据包(判断是否有数据丢失)

         7.1、查看数据包的最前面的操作码,如果是03说明数据没有错误,并且回复04和数据包编号

            在这里就可以创建本地一个文件,用来接收到对方发来的数据。但还不能开始写数据进去

          7.2、查看数据包的最前面的操作码,如果是05说明数据有错误。需要重新发

第八步:对比数据包编号,(第一次开始接收到数据包编号都是为1,第二次为2,以此类推)

         8.1,做判断,如果第一次接收到数据包编号为1,并且数据包的总字节为516,说明数据包顺序没有问题,可以写进本地一个文件里(此判断运用于下载文件大于512个字节的)并回复给服务器,04应答

          8.2做判断,如果第一次接收到数据包编号为1,并且数据包的总字节小于516,说明数据包顺序没有问题并且说明此数据包是最后一个,可以写进本地一个文件里,即下载完成。(此判断运用于下载文件小于512个字节的)并回复给服务器,04应答

四、服务器

4.1、事先准备好软件作为服务器 (端口号69)

4.2、案例:下载服务器下的dir文件夹中huai.txt(内容如下)

 五、TFTP对案例的使用

#include<stdio.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include<stdlib.h>
#include<string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define N 1024


void do_download(int sockfd,struct sockaddr_in mysockaddr)
{  

   	  socklen_t addrlen=sizeof(mysockaddr);
      char filename[30];

	  printf("please input do_download filename\n");
	 
 	  scanf("%s",filename);
 
      char buf[N]="";
      int flag=0;
	  int num=0;
	  ssize_t byte;
	  int fd;
  
      unsigned char ask_buf[50];
	  int ask_buf_text;
      
	 ask_buf_text= sprintf(ask_buf,"%c%c%s%c%s%c",0,1,filename,0,"octet",0);

     if(sendto(sockfd,ask_buf,ask_buf_text,0,(struct sockaddr *)&mysockaddr,addrlen)==-1)
      {
		  perror("fail to sendto for ask_buf");
		  exit(1);
		  
		  }

      
	  while(1)
	{	  
		if((byte=recvfrom(sockfd,buf,N,0,(struct sockaddr*)&mysockaddr,&addrlen))==-1)
		{
		 perror("fail to recvfrom_buf");
		 exit(1);
		 }
      if(buf[1]==5)
	  {
		  perror("recvfrom message fail ");
		  exit(1);
		  }
          	
	   if(buf[1]==3)
	{
		 if(flag==0)
		{
			if((fd=open(filename,O_RDWR|O_CREAT|O_TRUNC,0664))==-1)
			{
				perror("fail to open filename");
				exit(1);
				
				}
			  flag=1;
			}	 
		 
		  }
	 if((num+1== ntohs(*(unsigned short*)(buf+2))) &&  (byte==516))
		{
			num= ntohs(*(unsigned short*)(buf+2));
			if(write(fd,buf-4,byte-4)==-1)
			{
				 perror("fail to write");
				 exit(1);
				 }
               buf[1]=4;

			 if(sendto(sockfd,buf,4,0,(struct sockaddr *)&mysockaddr,addrlen)==-1)
			 {
				 perror("retall fail ");
				 exit(1);
				 }
			}
	   else if((num+1== ntohs(*(unsigned short*)(buf+2))) &&  (byte<516))
	   {
		     
			if(write(fd,buf-4,byte-4)==-1)
			{
				 perror("fail to write");
				 exit(1);
				 }
               buf[1]=4;

			 if(sendto(sockfd,buf,4,0,(struct sockaddr *)&mysockaddr,addrlen)==-1)
			 {
				 perror("retall fail ");
				 exit(1);
				 }
			
			 printf("do_download finish\n"); 

			   }
	
	   }
	}

int main(int argc ,char *argv[])
{
	if(argc < 2)
	{
		fprintf(stderr, "Usage: %s ip  and port \n", argv[0]);
	    exit(1);
	  }

	int sockfd;
	struct sockaddr_in mysockaddr;


	if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1)
	{
		perror("fail to sockfd");
		exit(1);
		}

    mysockaddr.sin_family=AF_INET;
	mysockaddr.sin_port =htons(69);
	mysockaddr.sin_addr.s_addr=inet_addr(argv[1]);
    
	
     do_download(sockfd,mysockaddr);
	 	
	return 0;
	  
	         }


运行结果

 运行命令:./a.out 10.152.194.124

please input do_download filename
huai.txt
do_download finish

在unbantu下的本地文件,出现了一个huai.txt 文件,内容与服务器的huai.txt一样

下载成功。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值