----------------------- Page 1-----------------------
第12卷第3期                              +,,。                            V01.12 No.3
20lo年3月                          鬣钎雾喾                              Mar.2010
doi:lO.3969/j.issn.1563--4795.2010.03.018
简单文件传送协议ITFTP)的C语言实现
谢永悠
(西南交通大学信息科学与技术学院,四川              成都610031)
摘  要:’rFTP(简单文件传送协议)是TCP/TP协议族中用来在客户机与服务器之间进行简单
文件传输的协议。文中给出了在visual C++6.0开发平台上,用C语言按照聊协议在服务器
跟多客户端之间进行文件传榆的实现方法。该方法可以传输超过32MB的文件。
关键词:Tnm:server;client;超时重传
0引言                                      1  系统所要解决的问题
利用TFrP简单文件传输协议可以实现Ⅱ’rP                  在唧文件的传输过程中,通常都要求有一
server与Tn’P client之间的文件传输.包括多客          定的容错能力。大部分的错误都会导致连接中
户的下载和上传请求。                              断。假如错误由一个错误的数据包引起.则这个
如果客户端发送的是下载请求,那么,服务                  包将不被确认,也不会被重新发送,因此,另一
器将根据客户端发过来的报文。解析出文件的路                    方将无法接收到。如果错误包丢失,则将使用超
径和文件名,并且根据解析出来的文件名,开始                    时机制。一般的错误主要是由三种情况引起:一
读文件并构造报文。然后再经过获取客户端发过                    是不能满足请求;二是收到的数据包内容错误,
来的端口号,把DATA报文发送给客户端;如果                  而这种错误又不能由延时或重发解释;三是对需
客户端发送的是上传请求,那么,服务器端也必                    要资源的访问丢失(如硬盘满)。
须解析出文件名及要保存的路径。若满足条件,                      椰只在一种情况下不中断连接,这种情况
则发送ACK给客户端以确认已经接受客户端的请                  是源端口不正确,在这种情况下。指示错误的包
求,然后等待客户的DATA报文。客户端接收                    会被发送到源机。事实上,Ⅱ耶协议的限制很
ACK后,就可开始发送数据报文。服务器开始解                  多.这些都是为了实现起来比较方便而进行的。
析报文。并将其写到指定的路径及文件中。
任何传输请求都来自一个读取或写入文件的   
2系统实现
请求,这个请求也是连接请求。如果服务器批准
2.1输入模块
此请求,则服务器将打开连接,数据以定长512
字节传输。每个数据包一般都含有一块数据,服                      输入模块可实现输入命令的接收、判断和容
务器发出下一个数据包以前.必须得到客户对上                    错处理,负责接收客户的输入信息并解析命令。
一个数据包的确认。如果一个数据包的大小小于                    并将接收到的命令存入结构体glptKeeplnput,以
512字节。则表示传输结束。如果数据包在传输                  供其他模块读取。
过程中丢失.则发出方会在超时后重新传输最后                      函数qiptlnputProgress(&glptKeeplnput)用于
一个未被确认的数据包。通信的双方都是数据的                    接收客户的输入。再把客户输入的命令、文件
发出者与接收者,其中一方传输数据接收应答,                    名、主机的ip地址保存到结构体中。其实现代码
另一方发出应答接收数据。                            如下:
typedef struct input p存放最终输入
命令的结构体木/
收稿日期:2009—10—21
删.eada.cn 2010.3电子元嚣件左用    55
万方数据
----------------------- Page 2-----------------------
第12卷第3期                              电手元嚣件盔用                                  V01.12 No.3
2010年3月                    Electronic Component&DeviceApplications            Mar.2010
{                                          INT8 bufer【SRV—PACKET_LENGTH】;
INT8 protoc【10];产协议木,                  接收数据。定义数据块大小为512字节:
INT8mode[5】;    产传输类型宰/              INT32 alen=sizeof(Client);
INT8 ipaddr【20】;p目的主机牛/                recvfrom(sock,(clear木)&RecvBuff,5 12,0,
INT8 option【4】;  ,幸操作类型木/          (struct sockaddr木)&Client,&alen);
INT8 source[301;p源文件名字宰/              获得客户端请求操作码:
INT8 dest【50】;  产操作后文件存              locakBuff_opcode=ntobs(Buff.opcode);
储地木,                                              打开本地文件:
pfile=fopen(path,”rb”);path为解析的路
径与文件名。
2.2  1'】51甲server模块
读本地文件:
本模块可调用构造报文模块,解析多个客户                            Fread(Buff,sizeof(char),5 1 2,pfile);
的请求,同时负责处理客户端请求,包括下载与                              填充TFTP首部:
上传。检查包号是否正确,并实现容错功能,从                              sendBuff.opcode=hton(3);操作码为3说明
而保证传输文件的正确性及可靠性。本模块的主                          是数据包:
要步骤的结构代码如下:                                        sendBuff.tu—block=htons(time);块号;
初始化Winsock库,注意要加上ws2—32.1ib库                  mencpy(&(sendBuff.th—data),FileBuff,i);数
文件:                                            据:
WSADTA WSAData;                                送文件给客户端f接收文件或数据与之类
WSAStartup(MAKEWORD(2,2),&WSADa—          似1:
ta);                                              Sendto(sock,  (char书)  &SendBuff,i+4,
创建套接字:                                    MSG_DONTROUTE,(struct sockaddr宰)&Client,
SOCKETsListen=INVALID——SOCKET;            sizeof(Client));
sListen=socket(AF_INET,SOCK DGRAM,            定义解析报文的函数.其中解析客户的请求
o);严这里用UDP协议,所以协议类型为                          代码如下:
SOCK—DGRAMo卑|                                          void  gtpGetWRrq  (char母type,char
初始化本地主机地址信息:                              file  name口,char buff口)
Struct sockaddr_in ServerAddr;                        {
ServerAddr.sin_family=AF_INET;                      inti,j;
ServerAddr.sin_addr=inet_addr(MYIp);/                *type=(buff[1】==’13  9"r7:,w7;判断
*MYIp为ip地址;,Ic/                                buff的前两位,如为1是读,如为2是写。
ServerAddr.sin_port=htons(69);        /              file_name D】=buff[i】;第三字节开始
木哪服务器默认端口号:乖/                                  就是文件名。
绑定套接字:                                            l
Bind(sock,(struct sockaddr幸)&ServerAddr,      解析接收到的buff中数据的代码如下:
sizeof(struct sockaddr_in));                      void gtpGetData(unsigned int木BKNUM,char
初始化远程地址信息:                                buff_data口,char buff口,char str口)
Struct sockaddr_in Client;                        {
Client.sin_family=AF_INET;                            inti,j;
Client.sin_port=htons(INADDR_ANY);                    宰BKNUM=getInt(buff+2);
Client.sin_addr.s_addr=inet_addr(RemoteIp)
;          for(i--4,j=0;j<5 12;i++’j++)
收到报文的缓存:                                              {
56  电子元器件主硐        2010.3 www.ecda.cn
万方数据
----------------------- Page 3-----------------------
第12卷第3期                                                                      V01.12 No.3
2010年3月                              最谛参巍                                    Mar.2010
把第四字节开始的512字节的值赋                    ReleaseMutex(g_signalfoflisO扩释放木/
给buff data的数据存储缓冲区中:                              return index;女II果成功就返回链表头
l                                        )
buff_data  IJ】=们’;—~                    g_signalfoflist=CreateMutex(0,0,”sin-
)                                    glelist”)扩保护链表指针水,
解析接收ACK的包号:                                  if(sgnApplicationOperator(fileName,type))
void  gtpGetAck(unsigned int宰BKNUM,        {/宰判断是否得到信号量,如果得到创建线
charbuff口)                                    程,Ic/
{                                          _beginthread(srvThreadFuction,0,(void木)
*BKNUM=getInt(buff+2)C/buff的第三      &threaddata)扩创建线程水/
第四位是ACK块号。                                        )
l                                      2.3 Tn[1PClient模块实现
gtpGetError 0解析接收到的ERROR的类
客户端的主要功能是解析输入模块的输人命
型。
令,读取相应的文件或写文件,并把根据解析得
void gtpGetError(charErrMsg【】,char buff 到的相应报文发到服务器端。邢客户端的实现
13);
主要体现在对T兀’P各种数据包首部字段的分析及
l
填充,填充(读,写)请求字段可以得到图1所示
缓冲区的信息存储gljErrMsgI约缓冲区
的读/写请求数据包格式。
中。
)                                                2bytes string 1 byte string 1 byte
解析接收客户请求的文件路径:
void iptGettPath(char file_name【】,char          OpcodeIFilenamel 0IModel0
path口)
图1读/写请求数据包格式
用多线程处理多客户的请求。若有客户请
求,就建立一个线程与该客户相对应,并把该线                            定义一个stpSetWRrq 0函数来填充请求字
程是读或写文件请求
的信息记录在一个链表中。                        段,把客户的请求保存到buff发送到服务器。其
一般要求用信号量来保护链表.要求读写链表时                        代码如下:
要遍历链表。对链表操作的时候还要求保护。每                            Int stpSetWRrq (char type,int  mode,char
一个线程负责与一个客户端通信。当客户端完成                        水filename,char*buffer,int size)
上传或下载后。线程结束。多线程主要是在接收                            (
到一个客户的请求后。要由服务器记录下客户的                              intij;
socket通信报文格式端口号与IP,并把这些信息保存起来,以建立与                            char str[4];
客户端的通信,直到线程结束。其主要的实现代                              buff【o】0=,07;
码如下:                                              buff【1】=(type=='r3 7’1 7:27;//分析是写还
/卑申请链表指针对文件进行操作乖/                        是读。(下载还是上传)
INT32 sgnApplicationOperator(INT8书曲le-        for(i=2,j=0;file_name  D]!=弋07;i++'j++)
Name,eonst INT32 opcode)                                /,把文件名保存到发送的buff中
f                                              memset(&str,0,4);
WaitForSingleObject(      g_signalforlist,    itoa(cCLIENTID,str,lO);
SNG—WAITE_TIME);胪申请信号量,Ic/                        for(i:.o;i<3;i++)
产如果文件没有被写,那么记录链表,如果                            //模式存储
没有该文件,或者是读,也记录链表,-c/                              }
伽聊.ecd瞳cn 2010.3电子元器件盔用        57
万方数据
----------------------- Page 4-----------------------
第12卷第3期                                    电手元嚣件主用                                          V01.12  No.3
2010年3月                        Electronic Component&Device Applications                    MaI".2010
图2所示是ACK包格式。其填充地段函数se.                                l
tACK 0:的代码如下:                                              客户端实现定时重传功能.就是在客户端下
载时发送下载请求报文或收到报文后发送ACK报
2bytes2bytes
文。若到设定时间还没有收到服务器端的下一个
数据报文,则重新发送该请求或者ACK报文。当
Block#
Opeode

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。