网络第3天

基于UDP的TFTP文件传输

功能:下载、上传、退出

#include <myhead.h>                                   
#define IP "192.168.8.100"                            
#define PORT 69                                       
                                                      
int download_file(int cfd,struct sockaddr_in sin);    
int upload_file(int cfd,struct sockaddr_in sin); 
                                                                                        
int main(int argc, const char *argv[])                
{                                                     
    //创建套接字文件                                  
    int cfd=socket(AF_INET,SOCK_DGRAM,0);             
    if(cfd<0){                                        
        ERR_MSG("socket");                            
        return -1;                                    
    }                                                 
    printf("socket create success\n");                
                                                      
    //填充地址信息体                                  
    struct sockaddr_in sin;                           
    sin.sin_family=AF_INET;                           
    sin.sin_port=htons(PORT);                         
    sin.sin_addr.s_addr=inet_addr(IP);                
                                                      
    //定义输入内容调用的函数                          
    char choose=0;                                    
    while(1){                                         
        printf("--------------------\n");             
        printf("-------1.下载-------\n");             
        printf("-------2.上传-------\n");             
        printf("-------3.退出-------\n");             
        printf("--------------------\n");             
        scanf("%c",&choose);                          
        while(getchar()!='\n'); //当不为\n时循环      
                                                      
        switch(choose){                               
        case '1':                                     
            download_file(cfd,sin);                   
            break;                                    
        case '2':                                     
            upload_file(cfd,sin);                     
            break;                                    
        case '3':                                     
            goto END;                                 
        default:                                      
            printf("输入错误请重新输入\n");           
        }                                             
    }                                                 
END:                                                  
    //关闭文件                                        
    close(cfd);                                       
                                                      
    return 0;                                         
}                                                     

 包的结构:

下载:

1、拼接 读操作 请求体,向服务器发送

2、服务器返回数据包,保存其中的块编号,并通过操作码判断是否是数据包,打印出错误码

3、将数据包的数据写入本地文件中

4、返回ACK包,ACK块编号为数据包的块编号

5、直到数据包小于516时,文件下载完毕

注意:ACK包总共就4个字节,发送给服务器的时候只能发4Bytes的包

//下载
int download_file(int cfd,struct sockaddr_in sin)
{
	char filename[20]="";
	printf("请输入需要下载的文件>>>");
	scanf("%s",filename);
	while(getchar()!='\n');

	//组包发送请求
	char buf[516]="";

	short* p1=(short*)buf;
	*p1=htons(1);  //操作码

	char* p2=buf+2;
	strcpy(p2,filename);//已经包含了'\0'就是后面那个0

	char* p3=p2+strlen(p2)+1;
	strcpy(p3,"octet");

	int size=2+strlen(p2)+1+strlen(p3)+1;

	if(sendto(cfd,buf,sizeof(buf),0,\
				(struct sockaddr*)&sin,sizeof(sin))<0){
		ERR_MSG("sendto");
		return -1;
	}
	printf("发送下载请求成功\n");

	//收数据
	struct sockaddr_in recvin;
	socklen_t len=sizeof(recvin);
	ssize_t res=0;
	short* ack=NULL;
	char Ack[4]="";
	int pd=0;
	//打开要写入的文件
	pd=open(filename,\
			O_CREAT|O_WRONLY|0664);
	while(1){
		bzero(buf,sizeof(buf));
		if((res=recvfrom(cfd,buf,sizeof(buf),0,\
						(struct sockaddr*)&recvin,&len))<0){
			ERR_MSG("recvfrom");
			return -1;
		}
		printf("res=%ld\n",res);
		printf("成功接收 [%s:%d] 数据\n",\
				inet_ntoa(recvin.sin_addr),ntohs(recvin.sin_port));

		p1=(short*)buf; //服务器返回的操作值
		ack=p1+1; //服务器返回的数据包编号
		//	printf("ack=%d\n",ntohs(*ack));

		if(ntohs(*p1)!=3){ //数据包操作码不对
			printf("数据包错误\n");
			if(ntohs(*p1)==5){ //5是报错包
				printf("ERRNO:%d\n",ntohs(*(p1+1)));
			}
			return -1; 
		}else{ 

			//将接收的数据写到文件里

			if(pd<0 && errno!=17){
				//	printf("ERR:%d\n",errno);
				ERR_MSG("open");
				return -1;
			}

			if(write(pd,buf+4,res-4)<0){
				ERR_MSG("write");
				return -1;
			}

			//返回ack包
			bzero(Ack,sizeof(Ack));
			p1=(short*)Ack;
			*p1=htons(4);
			*(p1+1)=*ack;
			if(sendto(cfd,Ack,sizeof(Ack),0,\
						(struct sockaddr*)&recvin,\
						sizeof(recvin))<0){
				ERR_MSG("sendto");
				return -1;
			}
			printf("返回ack包=%d成功\n",ntohs(*ack));
		}
	
		if(res<516){
			printf("下载完成\n");
			close(pd);
			break;
		}

	}
}

 

上传:

1、拼接 写操作 请求体,向服务器发送

2、服务器返回ACK包,通过操作码判断是否是ACK包,打印出错误码

3、拼接数据包,数据包编号从1开始ACK块编号是跟着数据包走的

4、将数据从本地文件中读出来,发送给服务器

5、直到从本地读出的数据小于512时,文件上传完毕

注意:用res控制包的大小,更灵活不会传空数据

//上传
int upload_file(int cfd,struct sockaddr_in sin)
{
	char buf[516]="";
	char name[100]="";

	printf("请输入要上传的文件名>>>");
	scanf("%s",name);
	while(getchar()!='\n');
	int pd_r=open(name,O_RDONLY);
	if(pd_r<0){
		ERR_MSG("open");
		return -1;
	}

	//组装请求数据包
	short* p1=(short*)buf;
	*p1=htons(2);

	char* p2=buf+2;
	strcpy(p2,name);

	char* p3=p2+strlen(name)+1;
	strcpy(p3,"octet");

	size_t size=2+strlen(name)+1+strlen(p3)+1;

	if(sendto(cfd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin))<0){
		ERR_MSG("sendto");
		return -1;
	}

	struct sockaddr_in recvin;
	socklen_t len=sizeof(recvin);
	short acknum=1;
	ssize_t res=0;
	char ack[4]="";

	while(1){
		//接收服务器返回数据
	//	bzero(buf,sizeof(buf));
		if(recvfrom(cfd,ack,sizeof(ack),0,\
					(struct sockaddr*)&recvin,&len)<0){
			ERR_MSG("recvfrom");
			return -1;
		}

	//	printf("%d\n",ntohs(*(short*)ack)); //4 服务器给的ack包
		if(ntohs(*(short*)ack)==5){
			printf("请求错误,ERRNO:%d\n",ntohs(*(short*)ack+1));
			return -1;
		}
	
		//发文件数据包
		bzero(buf,sizeof(buf));
		p1=(short*)buf;
		*p1=htons(3);

		*(p1+1)=htons(acknum);

		res=read(pd_r,buf+4,512);

		if(sendto(cfd,buf,res+4,0,\
					(struct sockaddr*)&recvin,len)<0){
			ERR_MSG("sendto");
			return -1;
		}
		if(res<512){
			printf("上传完成\n");
			close(pd_r);
			break;
		}
		acknum++;
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/267507.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

方法论系列:数据科学框架入门

目录 第一章 - 数据科学家如何战胜困难第二章 - 数据科学框架第三章 - 步骤1&#xff1a;定义问题和步骤2&#xff1a;收集数据第四章 - 步骤3&#xff1a;准备数据第五章 - 数据清洗的4个C&#xff1a;纠正、补全、创建和转换第六章 - 步骤4&#xff1a;使用统计学进行探索性…

Unity新动画系统之动画层和动画遮罩

Unity新动画系统之动画层和动画遮罩 一、介绍二、动画骨骼遮罩层使用第一种就是create一个avatar Mask,如下&#xff1a;第二种遮罩&#xff0c;就是直接在动画剪辑的属性上更改&#xff0c;如图一为humanoid类型的动画剪辑属性&#xff1a; 一、介绍 之前分享过FSM动画控制系…

组学无参比对教程

转录组无参比对教程 当作物是没有参考基因组时&#xff0c;需要无参进行比对。Trinity是现在使用最广泛的转录组De novo组装软件。 Trinity 是无参考转录组从头组装转录组的常用软件&#xff0c;且trinity的使用文档非常详细&#xff0c;整合的内容非常完整&#xff0c;包括从…

企业知识库在跨地域团队协作中的价值

随着全球化进程的不断加速&#xff0c;越来越多的企业开始面临跨地域协作的挑战。在这种背景下&#xff0c;企业知识库作为一种重要的知识管理工具&#xff0c;对于提高团队协作效率、促进知识共享与创新具有不可替代的价值。接下来就说一下知识库在跨地域团队协作中的重要性及…

OpenSSH升级指南:实战检验的步骤,有效加固服务器安全

在做服务器漏扫时我们经常会遇到有关于OpenSSH相关的安全漏洞&#xff0c;本文主要给大家介绍一下有关于OpenSSH的升级方法&#xff0c;小伙伴们可以参考一下流程&#xff0c;按步骤操作&#xff0c;但是过程中一定会遇到各种各样的问题&#xff0c;需要自行解决&#xff0c;这…

怎么为pdf文件添加水印?

怎么为pdf文件添加水印&#xff1f;PDF是一种很好用的文件格式&#xff0c;这种格式能够很有效的保护我们的文件&#xff0c;但有时可能还会被破解&#xff0c;这种时候在PDF上添加水印就是比较好的方法。 综上所述&#xff0c;PDF是保密性很强的文件&#xff0c;但添加水印能够…

二维码初体验 com.google.zxing 实现续 - web api封装

文章目录 一、概述二、最终效果三、源码结构四、完整代码 一、概述 在 二维码初体验 com.google.zxing 实现 我们实现了二维码的生成&#xff0c;但是大部分情况下&#xff0c;二维码的相关功能是作为API接口来提供服务的。 我们下面便演示在springboot、Knife4j下封装api接口…

【小沐学Python】Python实现Web服务器(aiohttp)

文章目录 1、简介2、下载和安装3、代码测试3.1 客户端3.2 服务端 4、更多测试4.1 asyncio4.2 aiohttpHTTP服务器4.3 aiohttp爬虫实例4.4 aiohttprequests比较 结语 1、简介 https://github.com/aio-libs/aiohttp https://docs.aiohttp.org/en/stable/index.html Asynchronous …

C/C++图型化编程

一、创建图形化窗口&#xff1a; 1.包含头文件&#xff1a; graphics.h:包含已经被淘汰的函数easyx.h:只包含最新的函数 2.两个函数就可以创建窗口&#xff1a; 打开&#xff1a;initgraph(int x,int y,int style);关闭&#xff1a;closegraph(); 3.窗口坐标的设置&#…

【眼镜】相关知识

眼镜相关 配眼镜可以事先了解的事情&#xff1a; 折射率&#xff1a;先说结论&#xff0c;高度数可以考虑选高折射率&#xff0c;低度数没必要。 折射率&#xff1a;1.50折射率 1.56折射率 1.60折射率 1.67折射率 1.71折射率 1.74折射率. 折射率越高&#xff0c;镜片越薄&a…

全面理解Stable Diffusion采样器

全面理解Stable Diffusion采样器 原文&#xff1a;Stable Diffusion Samplers: A Comprehensive Guide 在 AUTOMATIC1111 的 SD webui 中&#xff0c;有许多采样器&#xff08;sampler&#xff09;&#xff0c;如 Euler a&#xff0c;Heun&#xff0c;DDIM&#xff0c;… 什么是…

应急响应中的溯源方法

在发现有入侵者后&#xff0c;快速由守转攻&#xff0c;进行精准地溯源反制&#xff0c;收集攻击路径和攻击者身份信息&#xff0c;勾勒出完整的攻击者画像。 对内溯源与对内溯源 对内溯源&#xff1a;确认攻击者的行为 &#xff0c;分析日志 数据包等&#xff1b; 对外溯源&…

图像随机裁剪代码实现

原理 在计算机视觉领域&#xff0c;深度学习模型通常需要大量的训练数据才能获得良好的性能。然而&#xff0c;在实际应用中&#xff0c;我们可能面临训练数据不足的问题。为了解决这一问题&#xff0c;可以使用数据增强技术来扩充数据集。随机图像裁剪是其中一种简单而有效的…

系列十四、SpringBoot + JVM参数配置实战调优

一、SpringBoot JVM参数配置实战调优 1.1、概述 前面的系列文章大篇幅的讲述了JVM的内存结构以及各种参数&#xff0c;今天就使用SpringBoot项目实战演示一下&#xff0c;如何进行JVM参数调优&#xff0c;如果没有阅读过前面系列文章的朋友&#xff0c;建议先阅读后再看本篇文…

Windows系统安装 ffmpeg

下载及解压 ffmpeg官方下载地址&#xff1a;https://ffmpeg.org/download.html 下载好后将其解压至你想保存的位置中。 环境变量设置 打开Windows设置&#xff0c;在搜索框输入&#xff1a;系统高级设置。 新建环境变量&#xff0c;并输入bin目录具体位置。 安装检查 按住 w…

人工智能:从基础到前沿

人工智能&#xff1a;从基础到前沿 引言 当我们谈论“人工智能”&#xff08;AI&#xff09;时&#xff0c;我们其实是在谈论一个涵盖了众多学科、技术和应用的广阔领域。从计算机视觉到自然语言处理&#xff0c;从机器人学到深度学习&#xff0c;AI已经成为我们生活中不可或…

电脑上添加不了网络打印机的所有可能的原因,在这里差不多都能找到

在电脑上添加网络打印机通常很容易,但如果Windows无法很好识别或根本找不到它们呢?以下是一些快速解决方案。 无论你是升级到Windows 11还是仍在使用Windows 10,连接无线打印机都应该很容易。Windows应该能够自动连接到与你的电脑位于同一网络上的任何打印机。但有时,Windo…

大数据Doris(四十):聚合模型的局限性和ROLLUP的说明

文章目录 聚合模型的局限性和ROLLUP的说明 一、聚合模型的局限性

linux内存寻址原来那么简单

内存寻址 内存寻址听起来高大上&#xff0c;其实真实处理起来很简单&#xff0c;以常见的80x86架构为例&#xff0c;有三种不同的地址&#xff1a; 逻辑地址线性地址物理地址 内存控制单元(MMU)通过分段单元的硬件电路把一个逻辑地址转化为线性地址&#xff0c;通过分页单元的…

单例模式(C++实现)

RAII运用 只能在栈上创建对象 只能在堆上创建的对象 单例模式 设计模式 懒汉模式 解决线程安全 优化 饿汉模式 饿汉和懒汉的区别
最新文章