开发环境: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)实现效果:

基于c语言客户端的步骤,基于c语言tftp服务器与客户端实现相关推荐

  1. 客户端渲染换为服务器端渲染_服务器与客户端渲染(AngularJS与服务器端MVC)

    客户端渲染换为服务器端渲染 关于服务器与客户端应用程序渲染的讨论很多. 虽然没有"一刀切"的解决方案,但我将尝试从不同的角度主张客户端(特别是AngularJS). 首先是建筑. ...

  2. linux 安装nfs 客户端,在CentOS 7上安装NFS服务器和客户端

    NFS服务器和客户端安装在CentOS 7上 版本1.0 作者:Srijan Kishore 在Twitter上关注howtoing 最后编辑 16 / Dec / 2014 本指南介绍如何在Cent ...

  3. python客户端和服务端实验_结合服务器和客户端python

    我正在尝试使用python(稍后可能用c语言)和TCP套接字制作一个本地网络聊天程序. 我的目的是让服务器监听当前计算机的地址以获取传入消息,并将这些消息转发给客户端(我现在还不确定). 客户端将是一 ...

  4. Windows下的Tftpd32(Tftpd64)软件下载和使用教程-集成了Tftp服务器、客户端

    目录 一.概述 二.Tftpd32下载.安装 三.Tftpd32 使用教程  3.1 使用Tftpd32作Tftp服务器  3.2 使用Tftpd32作Tftp客户端 一.概述 Tftpd32是一个免 ...

  5. Ubuntu Linux操作系统tftp服务器和客户端安装(简单操作)

    操作系统:ubuntu(64位) 12.04,系统必须连接互联网! 以下绿色文字为终端输入命令,红色为错误信息,蓝色为提示信息,紫色为一般信息. 终端输入: tftp 192.168.1.102 发现 ...

  6. 单片机c语言程序编写步骤,用c语言编写单片机流水灯程序详解

    用C语言编写的流水灯程序 一.硬件电路 因为电路用单片机控制,所以电路非常简洁.其电路原理图见下图,印制板图如下图所示. 电路的核心部分是AT89C2051单片机,前面提到它有Pl和P3两组I/O口, ...

  7. c语言怎么做步骤循环,C语言基础教程之循环

    此程序已经陷入无限循环中,C语言基础教程之循环 当一段代码需要执行多次时,您可能会遇到这种情况.通常,语句按顺序执行:首先执行函数中的第一个语句,然后执行第二个语句,依此类推. 编程语言提供各种控制结 ...

  8. python写服务器端qt客户端_python写一些简单的tcp服务器和客户端

    代码贴上,做个记录 TcpClient # -*- coding:utf-8 -*- import socket target_host = "127.0.0.1" #服务器端地址 ...

  9. TFTP服务器与客户端的安装

    TFTP TFTP(Trivial File Transfer Protocol,简单文件传输协议)是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂.开销不大的文 ...

最新文章

  1. Vue组件基础知识总结
  2. js判断url链接是否可访问(服务可连接,可用)
  3. 重启服务器导致网站系统错误,win10怎么总是莫名其妙重启?_网站服务器运行维护...
  4. SQLSERVER事务日志已满 the transaction log for database 'xx' is full
  5. [Node.js] BDD和Mocha框架
  6. DELL H330(LSI 3008)RAID卡刷IT直通模式注意事项(避坑指南)
  7. 串口线的交叉直连之痛
  8. 纸箱制作机器人邮箱_纸箱机器人衣服制作方法
  9. ICON图标设计零基础到精通(UI进阶)
  10. 【uni-app】懂你找图--创建项目到首页推荐模块
  11. 使用flying saucer将html文件转成PDF
  12. winscp 同步_使用WinSCP进行简单代码文件同步
  13. 【元器件】电容选型指南
  14. APIAuto——敏捷开发最强大易用的 HTTP 接口工具 (二)
  15. 使用在线UML制作工具Freedgo Design设计uml例子
  16. JAVA开发的IDEA插件,让你的代码骚起来,你知道是哪九个插件咩?
  17. “拓界 成真”戴尔传递着Ta的“中国情”……
  18. 开发历程之让暴风雨来得更猛烈些吧!
  19. 3D Touch开发之App 快速入口标签(快捷菜单)
  20. PHP、JSP、ASP简介与区别

热门文章

  1. 蚂蚁集团回应与腾讯微信支付竞争;华为余承东:鸿蒙现达到安卓70-80%水平;C++20 标准草案获批准| 极客头条
  2. 2020 OpenInfra Days China 圆满落幕,100+ 全球大咖共话开源基础设施智未来
  3. Hadoop社区正式支持腾讯云COS,全球大数据开发者将无缝使用中国云存储
  4. 哟,2020 年了,用 Vue 做一个自己的小程序吧!| 原力计划
  5. Java 堆内存是线程共享的!面试官:你确定吗?
  6. 代码视角深入浅出理解 DevOps | 原力计划
  7. 漫画:如何给女朋友解释为什么200M宽带,打王者荣耀还是会有460的延迟?
  8. 315 后,等待失业的程序员
  9. 谷歌最新开源的工具可以自动化查找并修复 bug!
  10. 一文教你如何用 Python 将 iPhone “玩弄于股掌之中”!