【0810作业】Linux中基于UDP的TFTP文件传输(下载、上传)

news2024/11/24 2:50:47

一、tftp协议概述

简单文件传输协议,适用于在网络上进行文件传输的一套标准协议,使用UDP传输。

特点:

① 是应用层协议

② 基于UDP协议实现

③ 数据传输模式

  • octet:二进制模式(常用)
  • mail:已经不再支持

二、tftp下载模型

三、tftp协议分析

差错码:
    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.

四、TFTP通信过程总结

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

五、客户端下载文件(代码)

include <stdio.h>
include <head.h>
include <sys/types.h>
include <sys/socket.h>
include <arpa/inet.h>

define PORT 69 //服务器绑定的端口号
define IP "192.168.1.109" //"192.168.122.120" //服务器的IP地址
define FILENAME "5.png"

int main(int argc, const char *argv[])

   //创建报式套接字
   int cfd = socket(AF_INET, SOCK_DGRAM, 0);
   if(cfd < 0)
   {
       ERR_MSG("socket");
       return -1;
   }
   printf("cfd = %d\n",cfd);

   //绑定客户端的地址信息结构体到套接字上--->非必须绑定
   //若不绑定,则操作系统会给客户端绑定运行主机的IP和随机的端口号

   //填充要连接的服务器地址信息结构体,真实的地址信息结构体根据地址族制定
   //要发给谁,就填谁的地址信息
   //AF_INET : man 7 ip
   struct sockaddr_in sin;
   socklen_t addrlen=sizeof(sin);
   sin.sin_family         = AF_INET;      //必须填AF_INET
   sin.sin_port           = htons(PORT);  //端口号:服务器绑定的端口号
   sin.sin_addr.s_addr    = inet_addr(IP);//服务器绑定的IP

   //编辑读写请求
   char buf[516]="";
   char *ptr=buf;
   unsigned short *p1=(short*)buf;   //操作码
   *p1=htons(1);
   char *p2=buf+2;          //文件名
   strcpy(p2,FILENAME);
   char *p3=p2+strlen(p2); //第一个0 
   *p3=0;
   char *p4=p3+1;   //模式  
   strcpy(p4,"octet");
   size_t size=2+strlen(p2)+1+strlen(p4)+1; //操作码+文件名+0+模式+0

   size_t res=0;

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

   //创建下载文件并清空
   int fd=open("./1.png",O_WRONLY|O_CREAT|O_TRUNC,0664);
   if(fd < 0)
   {
       perror("open");
       return -1;
   }

   //循环收发,收文件,发送ack                                                                              
   while(1)
   {
       //接收数据包
       res = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&addrlen);
       if(res < 0)
       {
           ERR_MSG("recvfrom");
           return -1;
       }
       if(write(fd,buf+4,res-4) < 0 )
       {
           perror("write");
           return -1;
       }

       //发送ACK
       *p1=htons(4);
       if(sendto(cfd,buf,4,0,(struct sockaddr*)&sin,addrlen) < 0)
       {
           ERR_MSG("sendto");
           return -1;
       }
       if(res-4 < 512)
       {
           printf("download success\n");
           break;
       }
   }
   close(cfd);
   close(fd);
   return 0;   
}                                                                                                    

六、【全】代码(客户端下载、上传文件)

#include <stdio.h>
#include <head.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define PORT 69              //服务器绑定的端口号
#define IP "192.168.1.101" //服务器的IP地址

int do_download(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("cfd = %d\n",cfd);

	//绑定客户端的地址信息结构体到套接字上--->非必须绑定
	//若不绑定,则操作系统会给客户端绑定运行主机的IP和随机的端口号

	//填充要连接的服务器地址信息结构体,真实的地址信息结构体根据地址族制定
	//要发给谁,就填谁的地址信息
	//AF_INET : man 7 ip
	struct sockaddr_in sin;
	socklen_t addrlen=sizeof(sin);
	sin.sin_family         = AF_INET;       //必须填AF_INET
	sin.sin_port           = htons(PORT);   //端口号:服务器绑定的端口号
	sin.sin_addr.s_addr    = inet_addr(IP); //服务器绑定的IP

	char choose =0;
	while(1)
	{
		printf("------------------------\n");
		printf("---------1. 下载--------\n");
		printf("---------2. 上传--------\n");
		printf("---------3. 退出--------\n");
		printf("------------------------\n");
		printf("------------------------\n");
		printf("请输入>>> ");

		choose = getchar();
		while(getchar() != 10);   //循环获取字符,直到遇到\n结束循环

		switch(choose)
		{
		case '1':
			do_download(cfd,sin);
			break;
		case '2':
			//do_upload();
			break;
		case '3':
			goto END;
			break;
		default:
			printf("输入错误!请重新输入\n");

		}
	}
END:
	//关闭文件描述符
	close(cfd);

	return 0;
}

int do_download(int cfd, struct sockaddr_in sin)
{
	//组包准备发送下载请求
	char buf[516]="";
	char name[20]="";
	printf("请输入要下载的文件名>>> ");
	scanf("%s",name);
	while(getchar()!=10);

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

	char *p2=buf+2;          //文件名
	strcpy(p2,name);

	char *p3=p2+strlen(p2); //第一个0 
	*p3=0;

	char *p4=p3+1;   //模式  
	strcpy(p4,"octet");

	size_t size=2+strlen(p2)+1+strlen(p4)+1; //操作码+文件名+0+模式+0

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

	//创建下载文件并清空
	int fd = -1;   //必须初始化成一个无效的文件描述符
	socklen_t addrlen = sizeof(sin);
	ssize_t res = 0;
	unsigned short num = 0;  //记录本地的块编号

	//发送下载请求
	while(1)
	{
		//接收数据
		bzero(buf,sizeof(buf));
		res = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&addrlen);
		if(res < 0)
		{
			ERR_MSG("recvfrom");
			return -1;
		}

		if(3 == buf[1])  //数据包
		{
			//判断服务器返回的数据包的块编号与本地记录的块编号是否一致
			if(*(unsigned short*)(buf+2) == htons((num+1)))
			{
				num++;  //更新本地记录的块编号
				if(-1 == fd)
				{
					fd=open(name,O_WRONLY|O_CREAT|O_TRUNC,0664);
					if(fd < 0)
					{
						perror("open");
						return -1;
					}
				}

				//将数据写到文件中
				if(write(fd,buf+4,res-4) < 0 )
				{
					perror("write");
					return -1;
				}

				//发送ACK
				buf[1] = 4;
				//*p1=htons(4);
				if(sendto(cfd,buf,4,0,(struct sockaddr*)&sin,sizeof(sin)) < 0)
				{
					ERR_MSG("sendto");
					return -1;
				}
				//若接收到的数据小于512跳出循环,结束下载
				if(res-4 < 512)
				{
					printf("%s 文件下载完毕\n",name);
					break;
				}
			}
		}
		else if(5 == buf[1])    //错误包
		{
			printf("错误: %d %s\n",ntohs(*(short*)(buf+2)),buf+4);
			close(fd);
			return -1;
		}
	}
	close(fd);
	return 0;
}


 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

易服客工作室:PressMart – 现代Elementor WooCommerce WordPress商城主题

PressMart是现代且独特的 Elementor WooCommerce WordPress商城主题。它配备了高品质的 05 预建主页&#xff0c;适合任何在线商店&#xff0c;如时装店、电子产品商店、家具店等。 我们使用 Elementor – 一个拖放页面构建器&#xff0c;不需要用户的编码技能即可轻松编辑和构…

图解WebSocket

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱写博客的嗯哼&#xff0c;爱好Java的小菜鸟 &#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44d;三连支持&#x1f44d;一下博主哦 &#x1f4dd;个人博客&#xff1a;敬请期待 文章目录 前言一、…

使用phpstorm开发调试thinkphp

1.环境准备 1.开发工具下载&#xff1a;PhpStorm: PHP IDE and Code Editor from JetBrains 2.PHP下载&#xff1a;PHP: Downloads 3. PHP扩展&#xff1a;PECL :: Package search 4.用与调试的xdebug模块&#xff1a; Xdebug: Downloads xdebug模块&#xff0c;如果是php8以…

分类预测 | MATLAB实现GWO-BiLSTM-Attention多输入分类预测

分类预测 | MATLAB实现GWO-BiLSTM-Attention多输入分类预测 目录 分类预测 | MATLAB实现GWO-BiLSTM-Attention多输入分类预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.GWO-BiLSTM-Attention 数据分类预测程序 2.代码说明&#xff1a;基于灰狼优化算法&#xff08…

【JVM】对String::intern()方法深入详解(JDK7及以上)

文章目录 1、什么是intern&#xff1f;2、经典例题解释例1例2例3 1、什么是intern&#xff1f; String::intern()是一个本地方法&#xff0c;它的作用是如果字符串常量池中已经包含一个等于此String对象的字符串&#xff0c;则返回代表池中这个字符串的String对象的引用&#…

Redis缓存读写策略(三种)数据结构(5+3)

Redis缓存读写策略&#xff08;三种&#xff09; Cache Aside Pattern&#xff08;旁路缓存模式&#xff09; Cache Aside Pattern 是我们平时使用比较多的一个缓存读写模式&#xff0c;比较适合读请求比较多的场景。 写&#xff1a; 先更新 db然后直接删除 cache 。 读 : …

爆肝整理,性能测试方法与关键指标以及瓶颈定位思路,一篇贯通...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能测试方法 1、…

Mybatis 源码 ③ :SqlSession

一、前言 Mybatis 官网 以及 本系列文章地址&#xff1a; Mybatis 源码 ① &#xff1a;开篇Mybatis 源码 ② &#xff1a;流程分析Mybatis 源码 ③ &#xff1a;SqlSessionMybatis 源码 ④ &#xff1a;TypeHandlerMybatis 源码 ∞ &#xff1a;杂七杂八 在 Mybatis 源码 ②…

ubuntu 部署 ChatGLM-6B 完整流程 模型量化 Nvidia

ubuntu 部署 ChatGLM-6B 完整流程 模型量化 Nvidia 初环境与设备环境准备克隆模型代码部署 ChatGLM-6B完整代码 ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型&#xff0c;基于 General Language Model (GLM) 架构&#xff0c;具有 62 亿参数。结合模型量化技术&#x…

Go学习-Day1

Go学习-Day1 个人博客&#xff1a;CSDN博客 打卡。 Go语言的核心开发团队&#xff1a; Ken Thompson (C语言&#xff0c;B语言&#xff0c;Unix的发明者&#xff0c;牛人)Rob Pike(UTF-8发明人)Robert Griesemer(协助HotSpot编译器&#xff0c;Js引擎V8) Go语言有静态语言的…

Sentinel使用实例

不说了&#xff0c;直接上官方文档 https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md Sentinel Example 项目说明 本项目演示如何使用 Sentinel starter 完成 Spring Clo…

推荐工具!使终端便于 DevOps 和 Kubernetes 使用

如果你熟悉 DevOps 和 Kubernetes 的使用&#xff0c;就会知道命令行界面&#xff08;CLI&#xff09;对于管理任务有多么重要。好在现在市面上有一些工具可以让终端在这些环境中更容易使用。在本文中&#xff0c;我们将探讨可以让工作流程简化的优秀工具&#xff0c;帮助你在 …

Intel汇编和ATT汇编的区别?

一、前缀不同 在 Intel 语法中&#xff0c;没有寄存器前缀或立即前缀。 然而&#xff0c;在 AT&T 中&#xff0c;寄存器的前缀是“%”&#xff0c;而 immed 的前缀是“$”。 Intel 语法十六进制或二进制即时数据分别带有“h”和“b”后缀。 此外&#xff0c;如果第一个十六…

最新AI系统ChatGPT网站程序源码+搭建教程/公众号/H5端/安装配置教程/完整知识库

1、前言 SparkAi系统是基于国外很火的ChatGPT进行开发的Ai智能问答系统。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。 那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧&#xff01;…

nginx一般轮询、加权轮询、ip_hash等负载均衡模式配置介绍

一.负载均衡含义简介 二.nginx负载均衡配置方式 准备三台设备&#xff1a; 2.190均衡服务器&#xff0c;2.191web服务器1&#xff0c;2.160web服务器2&#xff0c;三台设备均安装nginx&#xff0c;两台web服务器均有网页内容 1.一般轮询负载均衡 &#xff08;1&#xff09…

基于深度信念神经网络的矿石产量预测,基于DBN的矿石产量预测,DBN的详细原理

目录 背影 DBN神经网络的原理 DBN神经网络的定义 受限玻尔兹曼机(RBM) DBN的矿石产量预测 基本结构 主要参数 数据 MATALB代码 结果图 展望 背影 DBN是一种深度学习神经网络,拥有提取特征,非监督学习的能力,是一种非常好的分类算法,本文将DBN算法进行矿石产量预测 DB…

golang Cobra 快速使用

package mainimport("fmt""os""github.com/spf13/cobra" )func f1(){fmt.Printf("这是主命令的运行函数 ") } func f2(){fmt.Println("这是一个子命令的运行函数") }func main(){var rootCmd &cobra.Command{Use: &quo…

【果树农药喷洒机器人】Part8:果树对靶变量喷药实验

&#x1f4e2;&#xff1a;博客主页 【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d; 收藏 ⭐不迷路&#x1f649; &#x1f4e2;&#xff1a;内容若有错误&#xff0c;敬请留言 &#x1f4dd;指正…

Maven - 全面解析 Maven BOM (Bill of Materials):打造高效依赖管理与模块化开发

文章目录 Whats BOMWhy Bom常見的官方BOMSpring Maven BOM dependencySpringBoot SpringCloud Maven BOM dependencyJBOSS Maven BOM dependencyRESTEasy Maven BOM dependencyJersey Maven BOM dependency How Bom定义BOM其他工程使用的方法 BOM VS POM What’s BOM BOM&…

jmeter中用户参数和用户定义的变量的区别

如果使用jmeter做过参数化的人都知道&#xff0c;参数化的方式有多种&#xff0c;其中一种就是使用用户定义的变量&#xff0c;还有一种是使用用户参数。那么&#xff0c;这两个有什么异同呢&#xff1f; 一、先说相同的点&#xff1a; 1、都可以参数化&#xff0c;以供sample…