基于c语言tftp服务器与客户端实现

news2024/11/27 16:53:41

开发环境:ubuntu

所用知识点:c,socket, tcp/ip协议

A)本实验主要实现tftp协议的服务器与客户端。

服务器实现功能有:

1)接收处理客户端请求,上传下下载文件

2)进行用户验证

3)对传输数据进行加密解密处理

4)生成日志文件

客户端实现功能有:

1)向服务器发出请求,上传或下载文件

2)对传输数据加密解密

3)对用户信息进行MD5加密

B)相关代码实现:

宏定下:

#ifndef MAKEWORD

#define MAKEWORD(l,h) ((unsigned short)(((unsigned char)(l))|(((unsigned short)(unsigned char)(h))<<8)))

#endif

#define WSA_MAJOR_VERSION 1

#define WSA_MINOR_VERSION 1

#define WSA_VERSION MAKEWORD(WSA_MAJOR_VERSION, WSA_MINOR_VERSION)

#define TFTP_OCTET 1

#define TFTP_WSTAT_FIRSTACK 0

#define TFTP_WSTAT_NEXTACK 1

#define TFTP_WSTAT_LASTACK 2

#define TFTP_RRQ 1 //读请求

#define TFTP_WRQ 2 //写请求

#define TFTP_DATA 3 //数据

#define TFTP_ACK 4 //ACK

#define TFTP_ERROR 5 //Error

#define MAX_RETRY 3 //大重复次数

#define TFTP_NOTEND_DATALEN 512+2+2 //数据块长度

//错误种类

#define Not_defined 0

#define File_not_found 1

#define Access_violation 2

#define Disk_full 3

#define Illegal_TFTP_operation 4

#define Unknown_port 5

#define File_already_exists 6

#define No_such_user 7

#define Time_out 8

#define Read_file_Error 9

#define Cannot_create_file 10

#define passwd_or_user_error 11

包的填充:

#include "define.h"

#include

#include

int makeack(unsigned short num,char *buffer,int size );

int makedata(unsigned short num,char *data,int datasize,char *buffer,int bufsize);

int makeerr(unsigned short num,char *buffer);

//ACK包填充

int makeack(unsigned short num,char *buffer,int size )

{

int pos = 0;

buffer[pos] = 0;

pos++;

buffer[pos] = TFTP_ACK; //操作码为04

pos++;

buffer[pos] = (char)(num>>8);//块号2个字节

pos++;

buffer[pos] = (char)num;

pos++;

return pos;

}

//Data包填充

int makedata(unsigned short num,char *data,int datasize,char *buffer,int bufsize)

{

int pos = 0;

buffer[pos] = 0;

pos++;

buffer[pos] = TFTP_DATA; //操作码为03

pos++;

buffer[pos] = (char)(num>>8);//块号

pos++;

buffer[pos] = (char)num;

pos++;

memcpy(&buffer[pos],data,datasize);//填充数据

pos = pos + datasize;

return pos;

}

//ERROR包填充

int makeerr(unsigned short num,char *buffer)

{

int pos=0;

buffer[pos]=0;

pos++;

buffer[pos]=TFTP_ERROR; //操作码为05

pos++;

buffer[pos] = (char)(num>>8); //错误种类号

pos++;

buffer[pos] = (char)num;

pos++;

return pos;

}

日志log.c实现

#include

static char log[100]; //日志

char datetime[20]; //记录时间变量

int timeout=2,retran=3; //服务器参数

void record(int a,struct sockaddr_in *sin,char *file)

{

char tem[60];

time_t t=time(0); //初始化日历时间

strftime(datetime,sizeof(datetime),"%y/%m/%d %X",localtime(&t));//将时间格式化

strcat(log,datetime);//将时间写入记录

//将字符串格式化

bzero(&tem,sizeof(tem));

if(a==1)

sprintf(tem," 收到来自 %s 上传文件 %s 的请求。\n",inet_ntoa(sin->sin_addr),file);

if(a==2)

sprintf(tem," %s 上传文件 %s 完毕。\n",inet_ntoa(sin->sin_addr),file);

if(a==3)

sprintf(tem," 收到来自 %s 下载文件 %s的请求。\n",inet_ntoa(sin->sin_addr),file);

if(a==4)

sprintf(tem," %s 下载文件 %s 完毕。\n",inet_ntoa(sin->sin_addr),file);

if(a==5)

sprintf(tem," 出现出错,操作中断。\n",inet_ntoa(sin->sin_addr),file);

//将具体信息写入记录

strcat(log,tem);

FILE *write;

if((write=fopen("log.txt","a+"))==NULL)

printf("打开记录文件失败\n");

//将记录写入文件

fwrite(&log,strlen(log),1,write);

fclose(write);

bzero(&log,sizeof(log));

}

加密解密实现

#include

#include

#include

int decrypt(FILE *in,FILE *out);

int encrypt(FILE *in,FILE *out);

unsigned char atoh(char *hexstr);

int encrypt(FILE *in,FILE *out)

{

if(in == NULL || out == NULL)

{

fprintf(stderr,"%s\n","file error!\n");

return -1;

}

unsigned char hex;

while(fread(&hex,1,1,in))

{

hex = ~hex^0x98;

fprintf(out,"%02X",hex);

}

return 0;

}

int decrypt(FILE *in,FILE *out)

{

if(in == NULL || out == NULL)

{

fprintf(stderr,"%s\n","file error!");

return -1;

}

unsigned char hexstr[3];

unsigned char hex = 0;

int i = 0;

while(fread(hexstr,2,1,in))

{

hex = atoh(hexstr);

hex = ~(hex ^ 0x98);

fwrite(&hex,1,1,out);

}

return 0;

}

/* convert string to hex */

unsigned char atoh(char *hexstr)

{

int i;

int hextodec[]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};

char chtodec[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};

unsigned char hexnum = 0;

for(i = 0; i < sizeof(chtodec); ++i)

{

if(hexstr[0] == chtodec[i])

{

hexnum += hextodec[i]*16;

}

}

for(i = 0; i < sizeof(chtodec); ++i)

{

if(hexstr[1] == chtodec[i])

{

hexnum += hextodec[i];

}

}

return hexnum;

}

上传数据:

//上传函数

void upload(struct sockaddr_in sour_addr,char buffer[])

{

char send_buffer[1024] = {0};

char recv_buffer[1024] = {0};

struct sockaddr_in dest_addr;

struct timeval timeout = {10,0};

int sour_len = 0;

int ret = 0;

int len = 0;

int flen = 0;

fd_set fdr;

unsigned short lastdata = 0;

unsigned short blocknum = 0;

FILE *file;

FILE *decrypt_file = NULL;

char filename[256];

//获取文件名

strcpy(filename,buffer+2);

dest_addr.sin_family = AF_INET;

dest_addr.sin_port = sour_addr.sin_port;

dest_addr.sin_addr.s_addr = inet_addr(desthost);//

//如果本地存在同名文件

if((file=fopen(filename,"rb"))!=NULL)

{

//发送一个error包,报告存在同名文件

printf("***存在同名文件***");

len = makeerr(File_already_exists,send_buffer);

ret = sendto(sock,send_buffer,len,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr));

record(5,&sour_addr,filename);

return;

}

//建立文件

if((file=fopen(filename,"w+b"))==NULL)

{

//如果失败,发送error包

printf("创建文件失败\n");

len = makeerr(Cannot_create_file,send_buffer);

ret = sendto(sock,send_buffer,len,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr));

record(5,&sour_addr,filename);

return;

}

//发送ACK

len = makeack(blocknum,send_buffer,sizeof(send_buffer));

ret = sendto(sock,send_buffer,len,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr));

blocknum++;

while(1){

FD_ZERO(&fdr);

FD_SET(sock, &fdr);

ret = select(sock+1, &fdr, NULL,NULL, &timeout);

if(-1==ret)

{

printf("Socket 错误\n");

fclose(file);

record(5,&sour_addr,filename);

return;

}

else

{

if(0==ret)

{

printf("超时\n");

fclose(file);

record(5,&sour_addr,filename);

return;

}

else

{

if (FD_ISSET(sock,&fdr))

{

//接收数据包

sour_len = sizeof(struct sockaddr);

ret = recvfrom(sock,recv_buffer,sizeof(recv_buffer),0,(struct sockaddr *)&sour_addr,&sour_len);

//如果是数据包

if(TFTP_DATA==recv_buffer[1])

{

lastdata = MAKEWORD(recv_buffer[3],recv_buffer[2]); //块号

//如果块号正确

if(lastdata == blocknum)

{

//发送ACK包

len = makeack(blocknum,send_buffer,sizeof(send_buffer));

sendto(sock,send_buffer,len,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr));

blocknum++;

if(blocknum > 65535)

blocknum = 0;

//后一包

if(ret < TFTP_NOTEND_DATALEN)

{

//写入文件

fwrite(&recv_buffer[4],1,ret-4,file);

flen = flen + ret -4;

#ifdef _DEBUG_

printf("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

printf("*****传输结束,共收到 %d 字节*****\n",flen);

#endif

rewind(file);

if((decrypt_file =fopen("decrypt_temp","wb+"))==NULL){

printf("decrypt file open error \n");

return;

}

decrypt(file, decrypt_file);

fclose(decrypt_file);

rename("decrypt_temp", filename);

fclose(file);

record(2,&sour_addr,filename);

return;

}

else

{

fwrite(&recv_buffer[4],1,512,file);

flen = flen + 512;

#ifdef _DEBUG_

printf("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

printf("已收到 %d 字节\n",flen);

#endif

}

}

else

{

//重新发送ACK包

printf("数据包块号错误.\n");

sendto(sock,send_buffer,len,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr));

}

}

}

}

}

}

}

C)客户端与服务都配有工程管理器,可通过make 完成编译。

D)实现效果:

嵌入式物联网需要学的东西真的非常多,千万不要学错了路线和内容,导致工资要不上去!

无偿分享大家一个资料包,

差不多150多G。里面学习内容、面经、项目都比较新也比较全!某鱼上买估计至少要好几十。(点击找小助理领取)

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

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

相关文章

TensorRT学习笔记--Ubuntu20.04安装TensorRT 8.2.5

目录 前言 1--查看本机环境配置 2--下载并安装Tensor RT 3--实例测试 3-1--验证Onnx模型的可用性 3-2--将Onnx模型转换为推理引擎engine 3-3--基于Tensor RT使用engine模型进行推理 4--参考 前言 推荐结合官方文档 3.2.3节中的Tar File Installation安装教程进行安装&a…

【docker09】镜像发布到docker私有库

镜像发布到docker私有库 1.Docker Registry 官方Docker Hub地址:https://hub.docker.com/&#xff0c;中国大陆访问太慢&#xff0c;并且具有被阿里云取代的趋势&#xff0c;不太主流Dockerhub、阿里云这样的公共镜像仓库可能不太方便&#xff0c;涉及机密的公司不可能提供镜像…

PDF如何转换成excel文档?这个方法很实用

PDF如何转换成excel文档&#xff1f;PDF文件是我们经常使用的文件之一&#xff0c;我们在很多工作场景都能接触到PDF文件&#xff0c;不过PDF文件并不能适用于各种情况&#xff0c;比如我们想对文件内的数据进行更改&#xff0c;我们就需要把PDF文件转换成excel表格再进行修改&…

js 生成条形码

简介&#xff1a; 通过js生成条形码 效果展示&#xff1a; 示例代码&#xff1a; <!-- Created by IntelliJ IDEA. User: songsir Date: 2018/11/26 Time: 10:49 --> <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8&…

分享一下我3个月收割大厂offer的一些经验总结

前几天&#xff0c;有位老粉私信我&#xff0c;说看到某95后学弟晒出阿里P7的工资单&#xff0c;他是真酸了…想狠补下技术&#xff0c;努力冲一把大厂。 为了帮到他&#xff0c;也为了大家能在最短的时间内做面试复习&#xff0c;我把软件测试面试系列都汇总在这一篇文章了。…

对抗搜索 学习笔记

先来看一道有意思题 situation 大意&#xff1a; 两个人玩井字棋&#xff0c;要求把所有位置填满后结束游戏。一方希望两者的连起来的线之差最多&#xff0c;一方希望最少。现在给定初始局面&#xff08;已经存在一些棋子&#xff09;以及先手&#xff0c;求最后的两者的连起…

SAP FICO预制凭证界面隐藏过账按钮

会计凭证一旦过账了就不能再进行修改&#xff0c;但其也提供了类似国内财务软件同样的预制功能&#xff0c;预制凭证过账之前不会更新会计系统。预制凭证虽然不更新科目余额&#xff0c;但同样会生成凭证编号&#xff0c;其凭证内容可以随意更改&#xff0c;也可以删除。一旦过…

bios设置u盘启动重装系统教程

​如今&#xff0c;大部分人都会采用U盘启动盘装系统&#xff0c;而使用U盘装系统之前&#xff0c;有一个很重要的步骤&#xff0c;那就是设置U盘启动。大部分电脑都可以直接通过u盘启动快捷键来选择U盘启动&#xff0c;少部分电脑只能通过bios设置u盘为第一启动项。那么&#…

支付宝的架构

自 2008 年双 11 以来&#xff0c;在每年双 11 超大规模流量的冲击上&#xff0c;蚂蚁金服都会不断突破现有技术的极限。2010 年双 11 的支付峰值为 2 万笔/分钟&#xff0c;到 2017 年双 11 时这个数字变为了 25.6 万笔/秒。 2018 年双 11 的支付峰值为 48 万笔/秒&#xff0c…

log4j2的使用

Log4j2的使用 概述 Apache Log4j 2是对Log4j的升级版&#xff0c;参考了logback的一些优秀的设计&#xff0c;并且修复了一些问题&#xff0c;因此带来了一些重大的提升&#xff0c;主要有&#xff1a; 异常处理&#xff0c;在logback中&#xff0c;Appender中的异常不会被应…

若依 ruoyi 配置多数据源 生成代码 导出代码

本文相关库说明&#xff1a;vue&#xff08;若依自带库&#xff09;db_game多数据源从库1db_paystore 多数据源从库2多数据源的情况下&#xff0c;想生成其他从库下数据库表对应的代码&#xff0c;但是若依自带的导入表中 是不会查询到从库各数据表信息的(只查询到若依框架对应…

我是这样解决 HBuilderX 安卓基座安装失败的问题

本文简介 点赞 关注 收藏 学会了 记录一个在使用 HBuilderX 开发 App 时遇到的问题。 同步资源失败&#xff0c;未得到同步资源的授权&#xff0c;请停止运行后重新运行&#xff0c;并注意手机上的授权提示 出现这个问题的原因是我把手机的 HBuilder App 给删掉了&#xff…

【自学Java】Java多维数组

Java多维数组 Java多维数组教程 Java 语言 中有 一维数组&#xff0c;也会有多维数组。如果有一个二维数组&#xff0c;那么数组的每个元素将会是一维数组&#xff0c;而不是单纯的元素。如果是一个多维数组&#xff0c;那么每个位置上面对应的是 纬度 - 1 的数组。 因为在平…

从官方文档学习Rabbit与SpringAMQP-乱版

本文也是笔者一直没有去详细学习的一个重要知识点MQ&#xff0c;也是架构中非常重要的一个中间件。 主要从Rabbit官网于Spring AMQP官方文档的角度去详细学习MQ 官方文档 Rabbit Spring AMQP 学习结果 测试项目地址 导读 本文主要从以下两个角度去学习MQ 一、RabbitMQ 官…

【nodejs】模块的加载机制

1、优先从缓存中加载 模块在第一次加载后会被缓存。意味着多次调用require()不会导致模块的代码被执行多次 注意&#xff1a;不论是内置模块、用户自定义模块、还是第三方模块&#xff0c;它们都会优先从缓存中加载&#xff0c;从而提高模块的加载效率。 &#xff08;1&#x…

【求证】 网上配镜靠谱吗?

肯定也有不少的小伙伴 看着网上琳琅满目的“明星同款”眼镜 心动不已 盘算着给自己弄一副“性价比” 最高“明星同款”那么网上配镜究竟靠不靠谱&#xff1f; 潍坊眼科医院眼健康管理中心提醒您 网上配镜需谨慎 网络平台的价格优势非常明显&#xff0c;部分销量高的店铺&#x…

二叉树基础计算

题目专题二叉树节点个数二叉树叶子节点个数二叉树第k 层节点个数二叉树查找值为x 的节点一共有这么几个题目&#xff0c;主要是用来表现题目的性质 分别是求 二叉树节点个数 二叉树叶子节点个数 二叉树第k 层节点个数 二叉树查找值为x 的节点 如果我使用的还是这个二叉树 其…

【linux】基础IO

文章目录一、复习文件相关知识二、复习C文件相关操作1、复习知识点2、复习操作三、文件的系统调用接口1、open2、write3、read小结四、文件描述符1、初步认识2、两个问题知识点3、文件描述符的分配规则五、重定向1、 dup2函数2、myshell里面实现重定向功能3、知识点六、如何理解…

【C++】stack、queue和deque

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《吃透西嘎嘎》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;stack 的…

密集单目 SLAM 的概率体积融合

点击进入—>3D视觉工坊学习交流群笔者简述&#xff1a;这篇论文主要还是在于深度估计这块&#xff0c;深度估计由于硬件设备的不同是有很多方法的&#xff0c;双目&#xff0c;RGBD&#xff0c;激光雷达&#xff0c;单目&#xff0c;其中最难大概就是单目了。在该论文中作者…