首页 > 其他分享 >基于UDP的tftp传输服务的客户端

基于UDP的tftp传输服务的客户端

时间:2024-11-14 19:50:44浏览次数:3  
标签:UDP struct int cfd 传输服务 tftp include buf sin

效果图

下载

上传:

代码:

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


#define SER_PORT 8888
#define SER_IP  "192.168.124.23"      // "0.0.0.0"

// 下载函数声明
int do_download(int cfd,struct sockaddr_in sin);
// 上传函数声明
int do_upload(int cfd,struct sockaddr_in sin);

int main(int argc,char **argv)
{
	if(argc < 2)
	{
		printf("please input ip\n");
		return -1;
	}

	// 创建数据报式套接字s
	int cfd = socket(AF_INET,SOCK_DGRAM,0);   // SOCK_DGRAM  配置udp协议
	if(cfd <0){
		fprintf(stderr,"__%d__",__LINE__);
		perror("socket");
		return -1;
	}
	printf("sokect success __%d__\n",__LINE__);
	
	// 允许端口快速重用
	int reuse = 1;  
	if(setsockopt (cfd, SOL_SOCKET,SO_REUSEADDR, &reuse,sizeof(reuse))<0)
	{
        fprintf(stderr, "__%d__ ", __LINE__);
        perror("setsockopt");
        return -1;
    }                                                                              
    printf("reuseaddr success __%d__\n", __LINE__);
	
	// 绑定客户端自身的地址信息,非必须绑定
	//若不绑定,则IP是当前运行环境的IP,端口号是随机端口(49152~65535)

	
	
	// 服务器的地址信息结构体---》port :69
	struct sockaddr_in sin;
	sin.sin_family		= AF_INET;
	sin.sin_port		= htons(69);
	sin.sin_addr.s_addr = inet_addr(argv[1]);
	
	
	int loop =1;
	int choose = 0;
	while(loop)
	{
		printf("*******************\n");
		printf("******1.下载*******\n");
		printf("******2.上传*******\n");
		printf("******3.退出*******\n");
		printf("******************\n");
		printf("请输入>>>");
		scanf("%d",&choose);
		while(getchar() != '\n');   // 循环吸收垃圾字符
		
		switch(choose){
			case 1:
				do_download(cfd,sin);
				break;
			case 2:
				do_upload(cfd,sin);
				break;
			case 3:
				loop = 0;
				break;
			default:
				printf("input err ,please re input\n");
			
		}
	}


	// 关闭

	close(cfd);    
	
	return 0;
}	

int do_download(int cfd,struct sockaddr_in sin)
{
	char filename[20] ="";
	memset(filename,0,20);
	printf("please input download filename:");
	scanf("%s",filename);
	while(getchar() != '\n');   // 循环吸收垃圾字符
	
	// 组下载请求包
	char require_buf[128] ="";
	short* p1 = (short*)require_buf;
	*p1 = htons(1);   // 操作码   代码下载操作
	
	char* p2 = require_buf+2;
	strcpy(p2,filename);   //文件名
	
	char* p4 =p2+strlen(filename)+1;
	strcpy(p4,"octet");   //模式
	
	int len = 2+strlen(p2)+strlen(p4)+1;
	
	//给服务器发送一个下载请求
	if(sendto(cfd,require_buf,len,0,(struct sockaddr*)&sin,sizeof(sin)) < 0)
	{
		fprintf(stderr,"line:%d",__LINE__);
		perror("sendto");
		return -1;
	}
	printf("sendto download require success __%d__\n",__LINE__);

	// 获取服务器的临时地址信息
	struct sockaddr_in dstaddr;
	int addrlen = sizeof(dstaddr);

	// 收到的数据包
	char data_buf[516];

	while(1){
		// 清空数据缓存区
		memset(data_buf+4,0,512);
		// 收数据包
		int res = recvfrom(cfd,data_buf,sizeof(data_buf),0,(struct sockaddr*)&dstaddr,&addrlen);   // 返回收到的字符
		if(res<0){
			fprintf(stderr,"__%d__",__LINE__);
			perror("recvfrom");
			return -1;
		}
		// 判断是否是对应的操作码
		short *data_p = (short*)data_buf; 
		short data_flag = ntohs(*(data_p+1));          //   存放块编号,在发送ack时会用到 
		char *write_p = data_buf+4;
		
		if(3 == ntohs(*data_p))
		{

			int fd = open(filename,O_WRONLY|O_CREAT|O_APPEND,0666);
			if(fd <0){
				printf("open err %s\n", strerror(errno));
				return -23;
			}
			// 写入文件
			
			int ret = write(fd, write_p,res-4);
			if(ret < 0 || ret != res -4){
				perror(" write err");
				return -25;
			}
			// 关闭文件
			ret = close(fd);			
			if(ret <0){
				perror("close err");
				return -25;;
			}
		}
		else if(5 == ntohs(*data_p)){
			// 编写当出现ERROR时的代码
			printf("Error from server: %s\n", data_buf + 4);
		
			return -1;
		}
		else{
			printf("操作码 err \n");
			return -1;
		}

		// 发ack
		char ack[4]="";
		short *ack_p = (short*)ack;
		short *ack_p_block = (short*)(ack+2);
		*ack_p = htons(4);            // 操作码,代表是ack应答包
		*ack_p_block = htons(data_flag);   //和数据包对应的块编号

		if(sendto(cfd,ack,4,0,(struct sockaddr*)&dstaddr,sizeof(dstaddr)) < 0)
		{
			fprintf(stderr,"__%d__",__LINE__);
			perror("sendto");
			return -1;
		}
		printf("sendto ack success%d\n",data_flag);
		
		// 判断数据长度是否小于512,若小于512结束循环。
		if((res-4) < 512)
			break;// 说明已经发送完了最后一个包,现在需要退出。
	}
	return 0;
}

int do_upload(int cfd,struct sockaddr_in sin){
	// 获取上传文件名
	char filename[20] ="";
	memset(filename,0,20);
	printf("please input upload filename:");
	scanf("%s",filename);
	while(getchar() != '\n');   // 循环吸收垃圾字符
	
	// 组上传请求包
	char require_buf[128] ="";
	short* p1 = (short*)require_buf;
	*p1 = htons(2);   // 操作码   代表上传操作
	
	char* p2 = require_buf+2;
	strcpy(p2,filename);   //文件名
	
	char* p4 =p2+strlen(filename)+1;
	strcpy(p4,"octet");   //模式
	
	int len = 2+strlen(p2)+strlen(p4)+1;
	
	//给服务器发送一个上传请求
	if(sendto(cfd,require_buf,len,0,(struct sockaddr*)&sin,sizeof(sin)) < 0)
	{
		fprintf(stderr,"line:%d",__LINE__);
		perror("sendto");
		return -1;
	}
	printf("sendto uplopad require success __%d__\n",__LINE__);

	// 获取服务器的临时地址信息
	struct sockaddr_in dstaddr;
	int addrlen = sizeof(dstaddr);

	// 收到的第一个应答包
	char ack_buf[4];
	// 清空数据缓存区
	memset(ack_buf,0,4);

	int res = recvfrom(cfd,ack_buf,sizeof(ack_buf),0,(struct sockaddr*)&dstaddr,&addrlen);   // 返回收到的字符
	if(res<0){
		fprintf(stderr,"__%d__",__LINE__);
		perror("recvfrom");
		return -1;
	}
	short *ack_make_p = (short*)ack_buf;
	short *ack_block_p = (short*)(ack_buf+2);
				
	if(0 != ntohs(*ack_block_p) || ntohs(*ack_make_p) != 4)
	{
		printf("make:%d,block:%d",ntohs(*ack_make_p),ntohs(*ack_block_p));
		printf("ack err");
		return -1;
	}
	printf("recv ack_pag success make:%d  block%d:__%d__\n",ntohs(*ack_make_p),ntohs(*ack_block_p),__LINE__);
	
	
		
	//给服务器发数据包
		
	//打开文件
	int fd = open(filename, O_RDONLY);
	if(fd<0){
		perror("open err");
		return -23;
	}
		
	char file_buf[516];    //来接收文件内容,组合上传数据包
		
	//组合数据包
	 
	short block_number =0;
	short *make_p = (short*)file_buf;
	*make_p = htons(3);         // 操作码
	short *block_p =(short*)(file_buf+2);  
		          
	
	// 循环获取文件内容,并将操作码和块编号组合
	while(1){
		*block_p = htons(block_number++);        //块编号 ,从1开始,一直往后加
		
		memset(file_buf+4,0,512);
		int ret = read(fd, file_buf+4, 512);
		if(ret <0) {
			perror("read err");
			return -3;
		}
			
		//给服务器发送数据包
		if(sendto(cfd,file_buf,516,0,(struct sockaddr*)&dstaddr,sizeof(dstaddr)) < 0)
		{
			fprintf(stderr,"line:%d",__LINE__);
			perror("sendto");
			return -1;
		}
		printf("sendto uplopad data_pag success __%d__\n",__LINE__);
		
		// 收到的应答包
		
		// 清空数据缓存区
		memset(ack_buf,0,4);
		// 收数据包的应答包
		res = recvfrom(cfd,ack_buf,sizeof(ack_buf),0,(struct sockaddr*)&dstaddr,&addrlen);   // 返回收到的字符
		if(res<0){
			fprintf(stderr,"__%d__",__LINE__);
			perror("recvfrom");
			return -1;
		}
		short *ack_make_p = (short*)ack_buf;
		short *ack_block_p = (short*)(ack_buf+2);
				
		if((block_number-1) != ntohs(*ack_block_p) || ntohs(*ack_make_p) != 4)
		{
			printf("make:%d,block:%d",ntohs(*ack_make_p),ntohs(*ack_block_p));
			printf("ack err");
			return -1;
		}
		printf("recv ack_pag success __%d__\n",__LINE__);
			

		// 代表文件已经读取完成
		if(ret < 512){
			if(close(fd)<0){
				perror("close");
				return -23;
			}
			break;
		}	
	}
	return 0;
}

标签:UDP,struct,int,cfd,传输服务,tftp,include,buf,sin
From: https://blog.csdn.net/qq_61958489/article/details/143776056

相关文章

  • UDP协议和TCP协议之间有什么具体区别?
    UDP(UserDatagramProtocol)和TCP(TransmissionControlProtocol)是两种常见的网络传输协议,它们在数据传输中有着显著的区别和适用场景。理解它们的区别对于网络工程师、软件开发人员以及网络安全专家都是至关重要的。本文会针对关于UDP和TCP之间区别的做出详细解释。一、协议概......
  • UDP 协议 - 学习笔记
    摘要:本文原创,转载请注明地址https://www.cnblogs.com/baokang/p/18543885一、UDP是什么UDP(UserDatagramProtocol)用户数据报协议是运输层协议的一种,是一种无连接的数据传输协议二、UDP协议的特点(1)UDP是无连接的,发送数据前不需要建立连接,因此减少的发生数据量和发送数据......
  • 基于surging 的木舟平台如何通过Tcp或者UDP网络组件接入设备
    一、概述     上篇文章介绍了木舟通过HTTP网络组件接入设备,那么此篇文章将介绍如何利用Tcp或者UDP网络组件接入设备.     木舟(Kayak)是什么?      木舟(Kayak)是基于.NET6.0软件环境下的surging微服务引擎进行开发的,平台包含了微服务和物联网平台。支......
  • 【网络】套接字编程——UDP通信
    >作者:დ旧言~>座右铭:松树千年终是朽,槿花一日自为荣。>目标:UDP网络服务器简单模拟实现。>毒鸡汤:有些事情,总是不明白,所以我不会坚持。早安!>专栏选自:网络>望小伙伴们点赞......
  • 计算机网络 - UDP 协议
    定义UDP(UserDatagramProtocol)用户数据报协议:是一种无连接的数据传输协议,传输前不需要建立连接,没有复杂的协议优点是:首部开销小,不需要连接,机制简单,可以一对一,一对多,多对一通信,使用与直播、视频通话等业务领域缺点是:传输无序,不能保证消息一定送到,有丢包的问题报文如下UDP报......
  • Air780E软件指南:UDP应用示例
    一、UDP概述UDP(用户数据报协议,UserDatagramProtocol)是一种无连接的、不可靠的传输层协议,主要用于实现网络中的快速通讯。以下是UDP通讯的主要特点:1.1无连接通讯:UDP在发送数据之前不需要建立连接,这大大减少了通讯的延迟。发送方只需将数据包封装成UDP报文,并附上目的地址......
  • 网络编程(一):UDP socket api => DatagramSocket & DatagramPacket
    目录1.TCP和UDP1.1TCP/UDP的区别1.1.1有连接vs无连接 1.1.2可靠传输vs不可靠传输 1.1.3面向字节流vs面向数据报1.1.4全双工vs半双工2.UDPsocketapi2.1DatagramSocket2.1.1构造方法2.1.2receive/send/close2.2DatagramPacket2.2.1......
  • 第一天打卡,udp协议
    今天学了udp协议基础,udp协议是一种无连接的网络协议,提供一种简单的方式来输送数据。发送:要用到的方法封装在InetAddress类中,其中DatagramSocket对象ds相当于快递员身份,不传递参数值的话会随机生成端口,进行输送快递(数据),快递的身份由DatagrampPacket对象充当,把东西打包。其中的......
  • 知识分享:Air780E软件之UDP应用示例
    一、UDP概述UDP(用户数据报协议,UserDatagramProtocol)是一种无连接的、不可靠的传输层协议,主要用于实现网络中的快速通讯。以下是UDP通讯的主要特点:1.1无连接通讯:UDP在发送数据之前不需要建立连接,这大大减少了通讯的延迟。发送方只需将数据包封装成UDP报文,并附上目的地址......
  • 面试:TCP、UDP如何解决丢包问题
    文章目录一、TCP丢包原因、解决办法1.1TCP为什么会丢包1.2TCP传输协议如何解决丢包问题1.3其他丢包情况(拓展)1.4补充1.4.1TCP端口号1.4.2多个TCP请求的逻辑1.4.3处理大量TCP连接请求的方法1.4.4总结二、UDP丢包2.1UDP协议2.1.1UDP简介2.1.2......