如何基于c语言tftp服务器与客户端实现_华清远见
- 格式:docx
- 大小:71.62 KB
- 文档页数:15
Tftp 服务器配置与使用TFTP (Trivial File Transfer Protocol,简单文件传输协议) 是TCP/IP 协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂、开销不大的文件传输服务。
它基于UDP 协议而实现,端口号为69。
此协议设计是基于实现小文件传输的目的。
因此它不具备通常的FTP 的许多功能,它只能从文件服务器上获得或写入文件,不能列出目录,不进行认证。
在嵌入式开发中,TFTP 服务常用于通过网线从PC 服务端的TFTP 目录中下载镜像文件到目标开发板中,以待烧写或运行.使用这种方式下载文件,操作方便,并且速度也较快.第一步:在终端下首先查看是否已安装tftp 服务器和客户端组件验证命令如下:[root@localhost ~]#rpm —qa | grep tftp需要出现如下已安装组件:tftp —0.39- 1 。
i386tftp-server —0.39 —1 。
i386第二步:安装tftp 组件如果没有安装tftp 组件,从linux 光盘中找到tftp 组件的rpm 包,分别为tftp-0。
39- 1.i386 。
rpm 和tftp—server —0.39- 1 。
i386 。
rpm.进入共享文件夹MyShare,将tftp 组件的rpm 包拷贝到根目录下的home 目录中,使用命令rpm —ivh [软件包的完整路径],完成安装。
[root@localhost home] #cp —rf /mnt/hgfs/MyShare/tftp_rpm ./[root@localhost home] # cd tftp_rpm[root@localhost tftp_rpm]#rpm —ivh [root@localhost tftp_rpm] #rpm —ivh tftp —server-0。
39- 1.i386 。
rpm tftp —0.39- 1.i386 。
用C#实现TFTP协议及其应用
明廷堂
【期刊名称】《电脑编程技巧与维护》
【年(卷),期】2013(000)009
【摘要】全面解读了TFTP协议的技术细节,并在此基础上运用C#语言完整实现该协议.通过一个TFTP客户端、服务器应用,在真实的网络管理环境中进行测试.项目保持完整性、独立性,为Socket编程开发基于网络协议的应用程序提供了一个基本思维框架.
【总页数】6页(P58-63)
【作者】明廷堂
【作者单位】
【正文语种】中文
【相关文献】
1.基于ARM的TFTP协议的实现 [J], 李小波;王健
2.简单文件传送协议(TFTP)的C语言实现 [J], 谢永悠
3.基于TFTP协议实现STM32的IAP [J], 孙晓晔;王程;成彬
4.在国际互联网上实现FTP与TFTP两种通信协议的比较 [J], 张西红;周其刚
5.基于TFTP协议的嵌入式系统开发方法设计与实现 [J], 汪小燕;连晓平;董燕;杨大鹏
因版权原因,仅展示原文概要,查看原文内容请购买。
实验实训大纲一、实验实训的目的和基本要求通过第一阶段的课程的学习,可以使学生对嵌入式linux 程序设计的基本编程规则与开发有一个比较全面的了解和认识,并最终能熟练掌握程序设计的理论知识和实际操作,也为以后学习更高一层的程序设计打下很牢固的理论知识基础和实践基础,尤其是有过硬的操作技术,较强的动手能力。
实验实训的基本要求是:1、严格按要求使用计算机等相关实验设备;2、通过实验实训提高动手操作能力;3、通过实验实训学会用专业知识分析问题、解决问题的基本方法和步骤;4、能够用理论指导实践;5、通过实验实训加深对理论知识的理解;6、能够掌握一定软件开发技术,具备一定的软件开发能力。
二、实验实训的内容及要求实验实训内容:1 .熟练掌握linux的基本命令和vi编辑器和gdb调试器的使用。
2、熟识c语言的运行环境,尤其是vi编辑器和gdb调试器的使用。
3、熟练掌握数据结构的使用.4.熟练掌握shell,Makefile的编写实验实训要求:1、掌握c语言,数据结构,shell,Makefile有关专业知识分析问题、解决问题的基本方法和步骤;2、能够所学知识的学习来理解程序设计的基本理论知识;4、能够熟练地使用第一阶段所学知识,为以后打下基础。
5、能够掌握一定软件开发技术,具备一定的软件开发能力。
三、考核形式及要求(一)日常实验考核1、实验过程占70%,实验结果占30%。
2、每单元实验结束为每个同学打出成绩,整个学期的平均成绩作为该同学的技能考核成绩;3、要求在规定时间内独立完成;四.实验实训教材及教学参考书目(一)推荐教材《C程序设计》谭浩强著《C程序设计题解与上机指导(第二版)》谭浩强著《GNU Makefile 编程》实验实训指导实验一Linux常用命令和vi,gdb的使用【实验内容】本课程要求学员对Linux基本操作命令有一定了解和掌握。
下面列出的一些常用命令作为参考。
最好针对每一个都能亲自练习、掌握。
C#基于TCP协议的服务器端和客户端通信编程的基础教程运⾏在TCP之上常见的⽹络应⽤协议有⽐如HTTP、FTP、SMTP、POP3、IMAP。
TCP是TCP/IP体系中最重要的传输协议,它提供全双⼯和可靠交付的服务,是⼤多数应⽤协议⼯作的基础。
TCP是⼀种⾯向连接(连接导向)的,可靠的,基于字节流的传输层通信协议。
TCP的⼯作过程建⽴连接传输数据连接的终⽌TCP的主要特点1.TCP是⾯向连接的协议2.是端到端的通信。
每个TCP连接只能有两个端点,⽽且只能⼀对⼀通信,不能点对多的的直接通信3.⾼可靠性4.全双⼯⽅式传输5.数据以字节流的⽅式传输6.传输的数据⽆消息边界关于线程利⽤TCP开发应⽤程序时,.net框架提供两种⼯作⽅式,⼀种是同步⼯作⽅式,另⼀种是异步⼯作⽅式。
同步⼯作⽅式是指利⽤TCP编写的程序执⾏到监听或者接收语句,在未完成当前⼯作前不再。
继续往下执⾏,线程处于阻塞状态,直到该语句完成后才能继续执⾏下⼀条语句。
异步⼯作⽅式是指程序执⾏到监听或者接收语句时,⽆论当前⼯作是否完成,都会继续往下执⾏。
TcpListener与TcpClient类常⽤⽅法与属性TCPListener类⽤于监听客户端连接请求,TCPClient类⽤于提供本地主机和远程主机的连接信息。
两个类都位于 .Socckets命名空间下。
1.TCPListener类常⽤的⽅法:(1)AcceptSocket:从端⼝处接收⼀个连接并赋予它Socket对象(2)AcceptTcpClient:从端⼝处接收⼀个连接并赋予它TCPClient对象(3)Equals:判断两个TcpListener对象是否相等(4)GetType:获取当前实例的类型(5)Pending :确定是否有挂起的连接请求(6)Start:开始接听传⼊的连接请求(7)Stop:关闭监听器(8)ToString:创建TcpListener对象的字符串表⽰2.TcpClient常⽤的属性与⽅法属性:(1)Client:获取或设置基础套接字(2)LingerState:获取或设置套接字保持连接的时间(3)NoDelay:获取或设置⼀个值,该值在发送或接收缓存冲未满时禁⽌延迟、(4)ReceiveBufferSize:获取或设置TCP接收缓存区的⼤⼩(5)ReceiveTimetut:获取或设置套接字接收数据的超时时间(6)SendBufferSize:获取或设置TCP发送缓存区的⼤⼩(7)SendTimeout:获取或设置套接字发送数据超时时间⽅法:(1)Close:释放TcpClient实例,⽽不关闭基础连接(2)Connect:⽤指定的主机名和端⼝号将客户端连接到TCP主机(3)BeginConnect:开始⼀个远程主机连接的异步请求(4)GetStream:获取能够发送和接收数据的NetworkStream对象TCP编程的⼀般步骤1.⽹络通信的最基本的前提就是客户端要先和服务器建⽴TCP连接2.服务端要不断的监听客户端是否有连接请求、并且服务端能要识别特定的客户端3.连接并创建对应的套接字4.发送数据和接收数据编写服务器端程序的⼀般步骤1.创建⼀个TcpListener对象,然后调⽤该对象的Start⽅法在指定的端⼝进⾏监听2.在单独的线程中,⾸先循环调⽤AcceptTcpClient⽅法接收客户端的连接请求,从该⽅法中的返回结果中得到与该客户端对应的TcpClient对象,并利⽤该对象的GetStream⽅法得到NetworkStream。
Ubuntu环境搭建(华清远见)tftp服务器搭建[1]基本原理tftp服务器最好搭建在Linux系统上面,这里是在虚拟机(ubuntu)上搭建tftp服务器,搭建步骤如下:1.确认虚拟机和外网连通2.安装tftp服务软件并启动3.配置tftp服务软件权限和参数4.本机验证tftp服务[2]具体过程1.确认网络连通在ubuntu上,安装软件需要网络的支持,所以安装软件前必须保证已经联网,且DNS配置正确。
检测命令如下:ubuntu@ubuntu:~/work$ ping –c4 PING (119.75.218.77) 56(84) bytes of data.64 bytes from 119.75.218.77: icmp_req=1 ttl=128 time=68.1 ms 表示网络和DNS已经配置正确2.安装tftp服务软件在ubuntu上,执行如下命令:ubuntu@ubuntu:~/work$ sudo apt-get install tftp-hpatftpd-hpatftp-hpa是客户端,tftpd-hpa是服务器3.确认tftp服务运行在ubuntu系统下,执行如下命令:ubuntu@ubuntu:~/work$ ps -ef | grep tftproot 1019 1 0 06:58 ? 00:00:00/usr/sbin/in.tftpd --listen --user tftp --address 0.0.0.0:69 --secure /home/ubuntu/work/tftpbootubuntu 10476 2841 0 17:29 pts/0 00:00:00 grep--color=auto tftp/usr/sbin/in.tftpd程序进程存在表示tftp服务运行成功。
4.修改tftp服务根目录如果想修改tftp服务的根目录,运行如下命令:ubuntu@ubuntu:~/work$ sudo vim /etc/default/tftpd-hpa会出现如下界面:TFTP_USERNAME="tftp"TFTP_DIRECTORY="/tftpboot"TFTP_ADDRESS="0.0.0.0:69"TFTP_OPTIONS="-c -s -l"修改TFTP_DIRECTORY="/tftpboot"这一行中引号中的路径,然后杀掉tftpd服务进程,命令如下:ubuntu@ubuntu:~/work$ sudo kill -9 `ps -ef | grep tftpd | grep root | awk '{print $2}'`或ubuntu@ubuntu:~/work$ sudo service tftpd-hpa restart ubuntu会自动重启服务,服务启动后,根路径设置就生效了。
C语言网络游戏开发服务器和客户端通信网络游戏开发在现代已经成为一个非常流行和受欢迎的领域。
在开发网络游戏时,服务器和客户端的通信是一个至关重要的方面。
C语言作为游戏开发的常用编程语言之一,对于服务器和客户端通信的实现也提供了丰富的功能和灵活性。
本文将介绍C语言中网络游戏开发中服务器和客户端通信的基本原理和常用方法。
一、基本原理在网络游戏开发中,服务器和客户端通信是通过基于网络协议的数据传输实现的。
常见的网络协议包括TCP/IP协议和UDP协议。
TCP/IP协议提供可靠的连接,在游戏中适用于需要保证信号传输的场景,如角色移动、战斗等。
UDP协议则提供了快速的数据传输,适用于实时性要求较高的场景,如聊天、广播等。
服务器和客户端之间通信的基本原理是通过建立Socket连接来进行数据传输。
Socket可以理解为服务器和客户端之间的通信接口。
服务器创建Socket并监听指定的端口,等待客户端连接;客户端则根据服务器的IP地址和端口号发起连接请求。
一旦连接建立成功,服务器和客户端就可以通过Socket进行双向数据传输。
二、服务器端通信实现服务器端通信的实现通常包括以下几个步骤:1. 创建Socket:服务器使用socket()函数创建一个Socket对象,并指定使用的协议和端口号。
2. 绑定地址和端口:将服务器的IP地址和端口号与Socket绑定,确保客户端可以连接到正确的地址。
3. 监听连接:使用listen()函数开始监听客户端连接请求。
服务器进入阻塞状态,等待客户端连接。
4. 接受连接请求:使用accept()函数接受客户端连接请求,并返回一个新的Socket对象用于与该客户端进行通信。
5. 数据传输:通过Socket进行数据传输。
服务器可以通过send()函数向客户端发送数据,通过recv()函数接收客户端发送的数据。
6. 关闭连接:通信结束后,服务器使用close()函数关闭Socket,释放资源。
如何基于c语言tftp服务器与客户端实现_华清远见如何基于c语言tftp服务器与客户端实现本篇文章主要的内容就是教大家,如何基于c语言tftp服务器与客户端实现,是非常精彩的内容,希望对大家的学习之路有所帮助。
TFTP(Trivial File Transfer Protocol,简单文件传输协议)是TCP/IP 协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂、开销不大的文件传输服务。
端口号为69。
开发环境: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#includeint makeack(unsigned short num,char *buffer,int size );int makedata(unsigned short num,char *data,intdatasize,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; //操作码为04pos++;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; //操作码为03pos++;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; //操作码为05pos++;buffer[pos] = (char)(num>>8); //错误种类号pos++;buffer[pos] = (char)num;pos++;return pos;}日志log.c实现#includestatic 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",localti me(&t));//将时间格式化strcat(log,datetime);//将时间写入记录//将字符串格式化bzero(&tem,sizeof(tem));if(a==1)sprintf(tem," 收到来自%s 上传文件%s 的请求。
如何在Linux下安装TFTP服务教程详解
本篇文章分享给大家,教你如何在Linux下安装TFTP服务,以下是教程详解,可以跟着步骤一步一步实现。
1、检测是否安装了TFTP服务
dpkg -s tftpd-hpa
本文引用地址:/Column/7447.html
2、如果未安装,需要
sudo apt-get install tftpd-hpa
3、修改配置文件 /etc/default/tftpd-hpa (注意:不同linux系统的配置文件不同)
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/tftpboot"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="-c -s -l"
tftp目录:/tftpboot
0.0.0.0表示任意IP可以访问
4、sudo service tftpd-hpa restart
5、做测试
将当前的1.txt文件传到/tftpboot目录下
Tftp 127.0.0.1
>put 1.txt
>quit
以上的教程就是讲解:如何在Linux下安装TFTP服务。
更多linux学习教程和资料,都可以在华清远见官网获得,华清远见提供免费的参考和学习。
TFTP协议解析简单文件传输协议的工作原理与应用场景TFTP协议解析:简单文件传输协议的工作原理与应用场景简介:简单文件传输协议(TFTP)是一种用于在计算机网络中传输文件的协议。
它是基于用户数据报协议(UDP)的简单、轻量级协议,主要用于在客户端和服务器之间传输小型文件。
本文将重点讨论TFTP协议的工作原理和应用场景。
一、TFTP协议的工作原理TFTP协议采用客户端-服务器模式,主要包含以下几个关键步骤:1. 封装请求:客户端向服务器发送读取或写入请求,并指定文件名和传输模式(如二进制或文本模式)。
2. 连接建立:服务器接受请求后,在特定端口上与客户端建立连接。
该端口通常为UDP端口69。
3. 数据传输:客户端和服务器通过TFTP协议进行数据传输。
在读取文件时,服务器将文件的块按顺序发送给客户端;在写入文件时,客户端将文件的块按顺序发送给服务器。
4. 错误处理:如果出现传输错误,TFTP协议会通过ERROR报文将错误信息传递给对方,并终止传输。
二、TFTP协议的应用场景TFTP协议由于其简单和高效的特性,被广泛应用于以下领域:1. 网络设备配置:TFTP协议常用于网络设备的配置和管理。
管理员可以使用TFTP将设备配置文件上传到服务器或从服务器下载配置文件。
这种方法可以实现批量配置更新和集中管理,提高配置的可靠性和一致性。
2. 无盘工作站引导:无盘工作站通常没有自己的硬盘,需要通过网络加载操作系统镜像。
TFTP协议可以提供快速和可靠的文件传输,使无盘工作站能够通过网络引导操作系统。
3. 固件升级:许多网络设备、交换机和路由器都支持通过TFTP协议进行固件升级。
管理员可以使用TFTP将新的固件文件传输到设备中进行更新,以提供新的功能和修复安全漏洞。
4. 日志传输:TFTP协议可以用于传输设备生成的日志文件。
管理员可以使用TFTP将设备日志上传到集中服务器进行存储和分析,以实现设备管理和故障排除。
总结:TFTP协议是一种简单而高效的文件传输协议,适用于需要快速、可靠传输小型文件的场景。
用tftp连接主机和开发板的学习过程交叉编译环境建立好了,总要琢磨着干点更好玩的吧,下一个目标就是要能把交叉编译成功的例子下载到学习板上来看看运行效果了。
1. 用minicom连接串口:fc12上默认是没有安装minicom的,yum安装一个很简单的了。
$ yum install minicom这样minicom就安装成功了。
运行:$ minicom -s出现如下界面:+-----[configuration]------+| Filenames and paths || File transfer protocols || Serial port setup || Modem and dialing || Screen and keyboard || Save setup as dfl || Save setup as.. || Exit || Exit from Minicom |+--------------------------+向下移动光标到Serial port setup 上,回车,进入Serial port setup 配置界面,如下:+-----------------------------------------------------------------------+| A - Serial Device : /dev/ttyUSB0 || B - Lockfile Location : /var/lock || C - Callin Program : || D - Callout Program : || E - Bps/Par/Bits : 115200 8N1 || F - Hardware Flow Control : No || G - Software Flow Control : No|| || Change which setting? |+-----------------------------------------------------------------------+配置完成以后直接保存退出就ok了。
教你编程实现TFTP协议Scuhkr/古开元四川大学信息安全研究所前言:不论你是热衷于黑客技术的爱好者, 还是从事编写网络应用程序的程序员, 都需要掌握熟练的编程能力, 以及具备扎实的TCP/IP协议的扎实基础. 很多初学者都有这样的经历,要么是能编一些复杂算法的程序,却不能结合到实际的应用中, 要么就是三卷W.Richard Stevens的圣经《TCP/IP详解》熟记于胸, 却无法用熟悉的编程语言将其实现. 这真是件很令人郁闷的事. 出于这样的目的, 本文就结合TCP/IP协议中的TFTP协议来分析, 并简单实现了Windows下TFTP的服务器和客户端.(致编者: 请务必加上以下声明)注: 本文大部分理论引用于<TCP/IP详解卷一>和中国协议分析网)一、协议分析:TFTP(Trivial File Transfer Protocol)即简单文件传送协议, 是TCP/TP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议, 提供不复杂的, 开销不大的文件传输服务.为了保持简单和短小, TFTP使用UDP协议, 且默认端口号为69,它不提供可靠的数据流传输服务, 也不提供存取授权与认证机制, 使用超时重传方式来保证数据的到达. 与FTP相比, TFTP的大小要小的多, 它主要用于小文件的传输, 只能从文件服务器上获得或写入文件, 不能列出目录. 更多的资料可以参考RFC1350.下图一给出了5种TFTP报文格式。
图一5种TFTP报文格式结合图一,我们可以看到,TFTP报文的头两个字节表示操作码。
对于读请求(RRQ)和写请求(WRQ),文件名字段说明客户要读或写的位于服务器上的文件。
这个文件字段以0字节作为结束。
模式字段是一个ASCII码串netascii或octet(大小写可任意组合),同样以0字节结束。
netascii表示数据是以成行的ASCII码字符组成,以两个字节—回车字符后跟换行字符(称为CR / LF)作为行结束符。
如何基于c语言tftp服务器与客户端实现本篇文章主要的内容就是教大家,如何基于c语言tftp服务器与客户端实现,是非常精彩的内容,希望对大家的学习之路有所帮助。
TFTP(Trivial File Transfer Protocol,简单文件传输协议)是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂、开销不大的文件传输服务。
端口号为69。
开发环境: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#includeint 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; //操作码为04pos++;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; //操作码为03pos++;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; //操作码为05pos++;buffer[pos] = (char)(num>>8); //错误种类号pos++;buffer[pos] = (char)num;pos++;return pos;}日志log.c实现#includestatic 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 的请求。
Windows下的TFTP服务器与客户端使⽤Windows下的TFTP服务器与客户端使⽤ 什么是Tftp Tftp全称为Trivial File Transfer Protocol,中⽂名叫简单⽂件传输协议。
⼤家可以从它的名称上看出,它适合传送“简单”的⽂件。
与FTP不同的是,它使⽤的是UDP的69端⼝,因此它可以穿越许多防⽕墙。
不过它也有缺点,⽐如传送不可靠、没有密码验证等。
虽然如此,它还是⾮常适合传送⼩型⽂件的。
让Tftp⾛上正途 通过Ttfp传送⽂件时,需要服务端和客户端。
⽐如我想从朋友的机器上下载⽂件,那就需要先把他的机器做成Tftp服务器,然后⽤我机器的客户端进⾏下载。
Windows 2000之后的操作系统⾃带有客户端,所以整个传送过程,事实上忙的是对⽅,哈哈!下⾯我以从朋友机器上下载⼀些图⽚为例来说明⼀下Tftp的使⽤过程。
1.设置服务端 说明⼀下,这⼀步是让你朋友操作的。
⾸先叫你的朋友把Tftpd32下载下来并解压(他可能很郁闷哦),然后打开Tftpd32,这时你朋友的机器就是⼀个Tftp服务器了。
软件默认Tftpd32的保存⽬录即为下载⽬录,换句话说,你要下载的⽂件需要放在Ttfpd32的保存⽬录下才能被客户端下载。
更改Tftpd32下载⽬录的操作⽅法为:点击右上⾓的“Browse”,然后选择要下载的⽂件的保存⽬录。
不过经此设置后,以后你要想从你朋友机器上下载⽂件,就要让他先把⽂件放在更改后的下载⽬录⾥,⽽不是Tftpd32的保存⽬录了。
如果你朋友搞不清当前下载⽬录下到底有哪些⽂件,可以让他点击右上⾓的“Show Dir”进⾏查看。
提⽰: a.要进⾏更⼈性化的设置,如下载的⼈数、下载端⼝等,可以点击“Settings”按钮;然后在“Tftp port(Tftp端⼝)”、“Max Retransmit(最⼤连接数)”等项上填写相应值,这⾥建议不要更改端⼝。
b.如果你要传的⽂件⽐较多,可以先让你朋友将它们打包,这样传起来⽐较⽅便。
tftp--实现服务器与客户端的下载与上传【转】项⽬功能:实现服务器与客户端的下载与上传,及linux系统下的tftp功能项⽬名称:tftp--实现服务器与客户端的下载与上传开发环境:linux /C开发⼯具:GCC/GDB⽹络协议:TCP/IP补充说明:程序中默认server端有upload⽂件夹⽤以接收client端上传的数据,client端有download⽂件夹⽤以下载server端的⽂件开发流程:编译流程: server.c -o server client.c -o client运⾏l流程:1. ./server 192.168.1.207(server ip) 8888(port)2. ./client 192.168.1.207 8888调试效果:client 端server 端1.server.c#include<stdio.h>#include<stdlib.h>#include<string.h>#include<stdio.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include<signal.h>#include<errno.h>#include <dirent.h>typedef struct {char cmd[10];int size;char buf[1024];}MSG;MSG msg;enum{list,get,put};int do_list(int connect_fd){char buf[1024];int n;int fd;DIR *pdir;struct dirent *pdirent;if((pdir = opendir(".")) == NULL){perror("Fail to open directory ");exit(EXIT_FAILURE);}while((pdirent = readdir(pdir)) != NULL){if(pdirent->d_name[0] == '.' )continue;strcpy(msg.buf,pdirent->d_name);msg.size = strlen(msg.buf);msg.size = send(connect_fd,&msg,sizeof(MSG),0); }msg.size = 0;send(connect_fd,&msg,sizeof(MSG),0);puts("send list successfully");return 0;}int do_get(int connect_fd){char filename[10];int n;int fd;struct stat fileinfo;if(recv(connect_fd,&msg,sizeof(MSG),0) < 0){perror("fail to recv");exit(EXIT_FAILURE);}if(stat(msg.buf,&fileinfo) < 0){perror("fail to stat");msg.size = -1;strcpy(msg.buf,strerror(errno));send(connect_fd,&msg,sizeof(MSG),0);return -1;}msg.size = fileinfo.st_size;strcpy(filename,msg.buf);puts("***********************");printf("send file size : %d\n",msg.size);printf("send filename : %s\n",msg.buf);puts("***********************");if(send(connect_fd,&msg,sizeof(MSG),0) < 0){perror("fail to recv");exit(EXIT_FAILURE);}if((fd = open(msg.buf,O_RDONLY)) < 0){fprintf(stderr,"Fail to open %s, %s\n",msg.buf,strerror(errno));exit(EXIT_FAILURE);}while(1){msg.size = read(fd, msg.buf,sizeof(msg.buf));send(connect_fd,&msg,sizeof(MSG),0);if(msg.size == 0)break;}printf("send file %s successfully\n",filename);return 0;}int do_put(int connect_fd){char buf[1024];int n;int fd;if(recv(connect_fd,&msg,sizeof(msg),0) <= 0){perror("fail to recv");exit(EXIT_FAILURE);}puts("**********************************");printf("upload filename : %s\n",msg.buf);printf("size: %d\n",msg.size);puts("**********************************");strcpy(buf,"./upload/");strcat(buf,msg.buf);if((fd = open(buf,O_WRONLY | O_CREAT | O_TRUNC,0666)) < 0) {perror("Fail to accept");exit(EXIT_FAILURE);}ftruncate(fd,msg.size);while(1){recv(connect_fd,&msg,sizeof(MSG),0);write(fd,msg.buf,msg.size);if(msg.size == 0)break;}printf("send file successfully!\n");exit(EXIT_SUCCESS);}int getcmd(char *pcmd){if(strcmp(pcmd,"list") == 0)return 0;if(strcmp(pcmd,"get") == 0)return 1;if(strcmp(pcmd,"put") == 0)return 2;}void do_task(int connect_fd,char *cmd){MSG msg;switch(getcmd(cmd)){case put:printf("recv file from client...\n");do_put(connect_fd);break;case get:printf("send file to client...\n");do_get(connect_fd);break;case list:printf("send file list to client...\n");do_list(connect_fd);break;default :break;}return;}int do_client(int connect_fd){MSG msg;int n;while(1){if((n =recv(connect_fd,&msg,sizeof(msg),0) )< 0){perror("fail to recv");exit(EXIT_FAILURE);}if(n == 0)break;do_task(connect_fd,msg.cmd);}exit(EXIT_FAILURE);}void signal_handler(int signum){waitpid(-1,NULL,WNOHANG);return;}int main(int argc, const char *argv[]){pid_t pid;int listen_fd;int connect_fd;socklen_t addrlen;struct sockaddr_in peer_addr;struct sockaddr_in server_addr;if(argc < 0){perror("fail to argc");exit(EXIT_FAILURE);}if(signal(SIGCHLD,signal_handler) == SIG_ERR){perror("fail to signal");exit(EXIT_FAILURE);}if((listen_fd = socket(AF_INET,SOCK_STREAM,0) )< 0) {perror("fail to socket");exit(EXIT_FAILURE);}memset(&server_addr,0,sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(atoi(argv[2]));server_addr.sin_addr.s_addr =inet_addr(argv[1]);if(bind(listen_fd,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0) //描述本机端⼝和IP,要知道数据包发往哪个进程{perror("Fail to bind");exit(EXIT_FAILURE);}if(listen(listen_fd,8 ) < 0)//监听连接的套接字,接收各客户端的请求,返回监听套接字⽂件描述符{perror("Fail to listen");exit(EXIT_FAILURE);}puts("listening ...");addrlen = sizeof(peer_addr);while(1){if((connect_fd = accept(listen_fd,(struct sockaddr *)&peer_addr,&addrlen)) < 0){perror("Fail to accept");//提取客户发过来的请求,返回新的已连接的套接字⽂件描述符exit(EXIT_FAILURE);}puts("*************************");printf("IP : %s\n",inet_ntoa(peer_addr.sin_addr));printf("PORT : %d\n",ntohs(peer_addr.sin_port));puts("*************************");if((pid = fork()) < 0){perror("Fail to listen");exit(EXIT_FAILURE);}if(pid == 0){do_client(connect_fd);}close(connect_fd);}exit(EXIT_FAILURE);}2.client.c#include<stdio.h>#include<stdlib.h>#include<string.h>#include<stdio.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include<errno.h>typedef struct {char cmd[10];int size;char buf[1024];}MSG;enum{list,get,put};int do_list(client_fd,pname){MSG msg;int fd;while(1){recv(client_fd,&msg,sizeof(MSG),0);if(msg.size == 0)break;printf("%s\n",msg.buf);}puts("get list successfully");return 0;}int do_get(int client_fd,char *filename){MSG msg;int fd;char buf[1024];strcpy(msg.buf,filename);if(send (client_fd,&msg,sizeof(MSG),0) < 0){perror("Fail to send");exit(EXIT_FAILURE);}recv(client_fd,&msg,sizeof(MSG),0);if(msg.size < 0){printf("Error :%s \n",msg.buf);return -1;}puts("***********************");printf(" download file size : %d\n",msg.size);printf(" download filename : %s\n",msg.buf);puts("***********************");strcpy(buf,"./download/");strcat(buf,msg.buf);if((fd = open(buf,O_WRONLY | O_CREAT | O_TRUNC,0666)) < 0) {fprintf(stderr,"Fail to open %s,%s\n",buf,strerror(errno));exit(EXIT_FAILURE);}ftruncate(fd, msg.size);while(1){recv(client_fd,&msg,sizeof(MSG),0);if(msg.size == 0)break;write(fd,msg.buf,msg.size);}printf("download file %s successfully\n",filename);return 0;}int do_put(int client_fd,char *filename){MSG msg;int fd;int n;if((fd = open(filename,O_RDONLY)) < 0){perror("Fail to open");exit(EXIT_FAILURE);}msg.size = lseek(fd,0,SEEK_END);strcpy(msg.buf,filename);lseek(fd,0,SEEK_SET);puts("**********************************");printf("filename : %s\n",msg.buf);printf("size :%d\n",msg.size);puts("**********************************");if(send(client_fd,&msg,sizeof(MSG),0) < 0){perror("Fail to send");exit(EXIT_FAILURE);}while(1){msg.size = read(fd,msg.buf,sizeof(msg.buf));if(send(client_fd,&msg,sizeof(MSG),0) < 0){perror("Fail to read");exit(EXIT_FAILURE);}if(msg.size == 0)break;}printf("upload file successfully!\n");return 0;}int getcmd(char *pcmd){if(strcmp(pcmd,"list") == 0)return 0;if(strcmp(pcmd,"get") == 0)return 1;if(strcmp(pcmd,"put") == 0)return 2;}int do_task(char *pcmd,char *pname,int client_fd){MSG msg;char buf[1024];int fd;switch(getcmd(pcmd)){case list:printf("get file list from the server ...\n");strcpy(msg.cmd,pcmd);if(send(client_fd,&msg,sizeof(MSG),0) < 0){perror("FAIL to send");exit(EXIT_FAILURE);}do_list(client_fd,pname);break;case get:printf("file %s is downloading from server ...\n",pname); strcpy(msg.cmd , pcmd);if(send(client_fd,&msg,sizeof(MSG),0) < 0){perror("FAIL to send");exit(EXIT_FAILURE);}do_get(client_fd,pname);break;case put:printf(" file %s is uploading to server ...\n",pname);strcpy(msg.cmd,pcmd);if(send(client_fd,&msg,sizeof(MSG),0) < 0){perror("Fail to send!");exit(EXIT_FAILURE);}do_put(client_fd,pname);break;default:break;}return 0;}int main(int argc, const char *argv[]){MSG msg;char buf[1024];char *pname,*pcmd;int client_fd;pid_t pid;int connect_fd;socklen_t addrlen;struct sockaddr_in server_addr;if((client_fd = socket(AF_INET,SOCK_STREAM,0) )< 0){perror("fail to socket");exit(EXIT_FAILURE);}memset(&server_addr,0,sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr =inet_addr(argv[1]);server_addr.sin_port = htons(atoi(argv[2]));if(connect(client_fd,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0) {perror("Fail to accept");exit(EXIT_FAILURE);}while(1){printf("tftp>");fgets(buf,sizeof(buf),stdin);buf[strlen(buf) -1] = '\0';if(strncmp(buf,"quit",4) == 0)break;pcmd = strtok(buf," ");pname = strtok(NULL," ");do_task(pcmd,pname,client_fd);}exit(EXIT_FAILURE);return 0;}。
如何基于c语言tftp服务器与客户端实现本篇文章主要的内容就是教大家,如何基于c语言tftp服务器与客户端实现,是非常精彩的内容,希望对大家的学习之路有所帮助。
TFTP(Trivial File Transfer Protocol,简单文件传输协议)是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂、开销不大的文件传输服务。
端口号为69。
开发环境: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#includeint 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; //操作码为04pos++;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; //操作码为03pos++;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; //操作码为05pos++;buffer[pos] = (char)(num>>8); //错误种类号pos++;buffer[pos] = (char)num;pos++;return pos;}日志log.c实现#includestatic 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#includeint 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;}//发送ACKlen = 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);#endifrewind(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 完成编译。