搭建简易客户端从tftp服务器中下载文件

tftp协议概述

        tftp(简单文件传输协议)是基于UDP适用于网络上进行文件传输的标准协议。

特点:

        应用层协议,基于UDP协议实现。

下载文件功能实现过程
1.服务器在69号端口等待客户端的请求。
2.客户端发送读写请求报文,服务器批准并使用临时接口与客户端进行通信。
3.服务器向客户端发送数据包并在数据包头设置块编码(可在客户端校验次序)。
4.客户端收到数据包后向服务器发送带有操作码和块编码的ACK
5.客户端校验收到的数据是否小于512byte,若小于则停止继续接收信息。

请求代码编写:

        客户端的请求代码由2byte的操作码+未知大小的文件名+0(1byte)+数据传输模式+0(1byte)组成本次通过字符串完成请求代码的编写

	//创建读请求包
	unsigned char buf[516]="";
	char *ptr = buf;
	short int * pa =(short int *)ptr;
	*pa = htons(1);//1为读2为写,并转化成网络字节序
	char *pb=ptr+2;
	strcpy(pb,filename);
	char * pc= pb+strlen(pb);
	char *pd=pc+1;
	strcpy(pd,"octet");

收发功能编写

由ACK与数据包的前4byte可见两者的3~4byte都存放块编码,获取ACK只需将从服务器接受到的数据包取前4byte再将操作码改为4即可。

 

while (1)
	{

		bzero(buf,sizeof(buf));
		//接收数据包
		
		res = recvfrom(sfd,buf,516,0,(struct sockaddr*)&sin,&addrlen);
		printf(" %ld ",n);
		n+=res;

		if (res<0)
		{
			ERR_MSG("recvfrom");
			return -1;
		}
	
		
				
			
			write(fb,buf+4,res-4);
		
			buf[1]=4; //将操作码改为4,pg的前四个字节就是ACK
		
			if(sendto(sfd,buf,4,0,(struct sockaddr*)&sin,sizeof(sin))<0)//发送ACK包
			{
				ERR_MSG("sendto");
				return -1;
			}
			if (res<516)
			{
				break;
			}
	
		


	}

总代码

#include <sys/types.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include  <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#define ERR_MSG(msg) do {\
	fprintf(stderr,"_%d_",__LINE__);\
	perror(msg);\
}while(0)

#define N 512
#define filename "5.png"



int main(int argc, const char *argv[])
{
	if (argc<3)
	{
		printf("请输入端口号和IP\n");
		return -1;
	}
	int port = atoi(argv[2]);
	
	//创建报式套接字
	int sfd =socket(AF_INET,SOCK_DGRAM,0);
	if (sfd<0)
	{
		ERR_MSG("socket");
		return -1;
	}
	printf("create socket success\n");
	
	
	
	
	//填充地址信息结构体,真实的地址信息结构体与协议族有关
	//AF_INEt 详见 man 7 ip
	struct sockaddr_in sin;
	sin.sin_family 	 =AF_INET;
	sin.sin_port  =htons(port);//主机字节序转网络字节序的端口号
	sin.sin_addr.s_addr = inet_addr(argv[1]);
	
	
	

	
	
	
	//创建读请求包
	unsigned char buf[516]="";
	char *ptr = buf;
	short int * pa =(short int *)ptr;
	*pa = htons(1);//1为读2为写,并转化成网络字节序
	char *pb=ptr+2;
	strcpy(pb,filename);
	char * pc= pb+strlen(pb);
	char *pd=pc+1;
	strcpy(pd,"octet");
	size_t sz = 2+strlen(pb)+1+strlen("octet")+1; //数据包大小
	//发送下载请求
	if(sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin))<0)
	{
		ERR_MSG("sendto");
		return -1;
	}
	int fb= open("./5.png",O_WRONLY|O_CREAT,0664);//创建一个文件将读取到的数据写入该文件
	

	socklen_t addrlen= sizeof(sin);

	ssize_t res=0;
	long  int n=0;
	

	while (1)
	{

		bzero(buf,sizeof(buf));
		//接收数据包
		
		res = recvfrom(sfd,buf,516,0,(struct sockaddr*)&sin,&addrlen);
		printf(" %ld ",n);
		n+=res;

		if (res<0)
		{
			ERR_MSG("recvfrom");
			return -1;
		}
	
		
				
			
			write(fb,buf+4,res-4);
		
			buf[1]=4; //将操作码改为4,pg的前四个字节就是ACK
		
			if(sendto(sfd,buf,4,0,(struct sockaddr*)&sin,sizeof(sin))<0)//发送ACK包
			{
				ERR_MSG("sendto");
				return -1;
			}
			if (res<516)
			{
				break;
			}
	
		


	}
	close(sfd);
	close(fb);



	return 0;
}

测试结果

        编译运行后通过eog图片可见图片下载成功。

在服务器中也显示传输完成

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值