现在的位置: 首页 > 综合 > 正文

关于文件传送类程序的思路和流程(转贴)

2013年11月27日 ⁄ 综合 ⁄ 共 4125字 ⁄ 字号 评论关闭

其实方法很多,就是找不道最完美的。。

经常在BBS上看到关于文件传送的讨论,这里把我的一个用UDP协议写得文件传送程序的有关思路发表出来,以期抛砖引玉。(这里虽然是用UDP协议写的,不过思路同样适用于其它通信方式如串口)。

文件传送的基本思路是把文件分成大小适当的数据块,每一次传送一个数据块。每一块数据有一个校验码,接收方根据校验码校验收到的数据块是否正确无误。同时为了能够保证数据块的正确顺序,还要表示数据块的序号。把有关信息组成一个个数据包,通过发送、接收方的正确处理,保证整个文件传输的快速、准确。
一、 数据包结构:
typedef struct
{
char FileFlage[6]; //标志:文件传送类数据包的第一个字节是“F”
unsigned short CRC; //校验码
long Size; //数据长度
long Position; //文件指针
char Data[1000]; //数据区
} TSendFileData;
说明:
1、标志:表示这个数据包的类型(详细说明见后)。
2、校验码:一般情况下,校验码放在整个数据包的最后面。这里把它放在这里的原因是由于数据包的长度不定,操作略有不便,所以放到这里。注意在计算校验码时要先把这个字段清零,然后再计算。至于校验码的形式,建议采用CRC校验方式。我这里是CRC16方式。也可以用其它校验方式。
3、数据长度:指明数据区中实际数据的字节数。
4、文件指针:指明本数据区中的数据块在被传文件中的文件指针位置。(这个字段在不同类型的数据包中有不同的意义,也就是在传送一些特殊数据包时,利用这个字段传输一些特殊的数据(详细说明见后)。
5、数据区:要传送的数据块。数据的大小,要考虑所采用的传输方式的误码率和传输效率。在UDP方式下,资料建议在1024以内,所以这里是1000字节。

二、数据包类型:
全部数据包分为发送方数据和接收方数据两大类,分别以FS和FR开头。
1、发送方指令以FS开头。
a)FSName:数据包内容是要发送的文件名和文件长度。
FileFlag=”FSName”,Size=文件名长度,Position=文件长度,Data=文件名。
b)FSFile:数据包的内容是被传送文件的数据块信息。
FileFlag=”FSFile”,Size=数据块长度,Position=对应文件的指针位置。Data=文件数据块,除最后一块的长度可能小于1000外,其余长度都是1000。
c)FSStop:发送方通知接收方,接收方所要求的数据块已经发送完毕。
FileFlag=”FSStop”,Size=0,Position=无效,Data=无效。
d)FSCanc:发送方通知接收方中断传输。(一般是发送方用户干预,中断传输)。
FileFlag=”FSCanc”,Size=0,Position=无效,Data=无效。
e)FSRepa:发送方收到接收方传来的数据有错误,通知接收方重发。
FileFlag=”FSRepa”,Size=0,Position=无效,Data=无效。
2、接收方指令以FR开头。
a)FRReje:接收方拒绝接收文件。
FileFlag=”FRReje”,Size=0,Position=无效,Data=无效。
b)FRRead:通知发送方按照指定的块号发送文件数据块。块号组成一个整型数组,存放在Data数据区。一般情况下,一次可以发送的块号数量=数据区长度/sizeof(int)=1000/4=250个。
FileFlag=”FRRead”,Size=sizeof(int)*所需数据块数量,Position=无效,Data=数据块号数组。
c)FREnd:通知发送方整个文件传送完毕。
FileFlag=”FREnd”,Size=0,Position=无效,Data=无效。
d)FRRepa:接收方收到的数据有错误,通知发送方重发。
FileFlag=”FRRepa”,Size=0,Position=无效,Data=无效。
e)FRErr:接收方建立或写文件出错,通知发送方。
FileFlag=”FRErr”,Size=0,Position=无效,Data=无效。
f)FRCanc:通知发送方收到中断命令。
FileFlag=”FRCanc”,Size=0,Position=无效,Data=无效。

二、通信流程:
1、发送方发出[FSName]命令。
2、接收方如果拒绝接收文件,则发送[FRReje]。否则按照指定的文件名建立文件。按照文件长度计算要分的文件块数量,按块数量建立一个块号数组,用来表示已经接收到的文件块。
3、接收方搜索块号数组中未收到的块号,把它组成一个要发送的块号数据,用[FRRead]命令把这个块号数据发发给发送方。
4、发送方按照块号数据读取文件,并发送每一个数据块[FSFile]。
5、接收方把正确收到的数据块按块号写入文件,并把相应的块号数组元素置成已接收。
6、循环执行4-5。
7、当发送方把块号数据中要求的数据块全部发送完毕后,发出[FSStop]命令,通知接收方指定的块号已经发送完毕。
8、循环执行3-7。
9、如果接收方搜索块号数组中已经没有未接收的数据块,则发送[FREnd]通知发送方文件已经全部传送完毕。
10、如果在传送过程中,发送方要强行中断传送,则发出[FSCanc]命令。接收方中断文件接收,并回应[FRCanc]。
11、如果接收方在建立或写文件中出错,发送[FRErr]通知发送方文件错误。
12、如果收到的数据包(不论是发送方还是接收方)发生校验错误,则用[FSRepa]或[FRRepa]通知对方重发最后一个数据包。
三、几点说明:
1、由于通信过程中不可避免地会出现错误,因此需要对收到的数据包进行校验。如果正确,则通知对方继续发下一个数据包,如果错误,则通知对方重发当前数据包。
2、如果对方在制定的时间内没有返回回应,则说明丢失了数据包,发出数据包的一方应当主动重发最后一个数据包。
3、但是这种一来一往的通信方式,大大降低了通信速度。为了能够尽量提高速度,同时又保证数据的准确完整。对于除[FSFile]以外的命令按照如上这种一来一往的方式来保证数据传送的准确可靠。
4、对整个文件传送过送过程中使用最多的[FSFile]命令,采取不进行应答方式的传送。发送方只管把所需要的数据块连续发出去,而不管接收方是否正确接收。而接收方根据块号数组清除地掌握着还需要重新传送那些块号的数据块。每发一次[FRRead]命令可以包含250个所需块号,而发送方就要发送250个[FSFile]。实践证明,这种方式的文件传送速度很快,而且很可靠。

以上所述只是文件传送程序的主要思路,还可以再扩展比如断点续传、文件下载等功能。希望大家讨论。

---------------------------------------------------------------

没有仔细看,不错
我们这儿传送文件,对比较重要的也是采取较验的方法,一发,一校验,否则,很难保证传输的正确性
---------------------------------------------------------------

××××××××××××××××××××
楼主结帐了请通知我,我帮你你加入精华区
××××××××××××××××××××
---------------------------------------------------------------

char FileFlage[6];改为
int FileFlage;

#define FSName 0x01
....
判一个int要比判一个字符数组要合理。
---------------------------------------------------------------

我个人认为
CRC校验简直多余
包的大小要看应用在什么地方,如果是在局域网,大于5000字节都可以,如果是跟外网传输,1000都算大了,有些网关都通不过。
最后提一点,一来一往的方式也不是很行的,如果是在局域网,几乎不掉包,一来一往几乎都可以省略,而对于外网,可能几来几往都还是不行。问题在于你用udp,双方都有可能互相丢包。惨!这种情况下,你想保证通讯的正确性,还得慢慢地设计很多东西。

---------------------------------------------------------------

不确认还是有问题的,发送方(S)永远也不知道接收方(R)的状态,如果(R)故障,(S)就一直等待,保持一个文件句柄。
就像有人对你说:“在公司等我,办完事来找你。”结果他临时有事不回来了……
但如果换过来的话就成了,你告诉他:“我等你五分钟,不然就处理其它事情了。”
---------------------------------------------------------------

在下拙见:
我觉得楼主采用的“接收方批量请求未收到的数据”,通常情况下,确实会比接收方、发送方每传输数据一次就应答一次节省时间。
但是,正如“shadowstar(天作棋盘星作子,谁人敢下?) ”老兄所言,如果接收方的批量传输请求没有被发送方接收到呢?那发送方就不知道要重传什么数据了。这时,区别就产生了。
“每次应答”的情况,会在一定的超时设置下,自动重发数据。而“批量应答”的情况就必须想办法保证发送方一定能接收到批量重发的请求,否则,就一直等待下去了。如果,不处理好这点,反而传输效果不如“每次应答”。
不知,楼主已经有何良策处理这种情况。

---------------------------------------------------------------

我刚查了一下,
首先CRC确实可以纠错,但是它的纠错能力有限。

转自:
http://www.libnet.sh.cn/keven/know/cdrom.htm
采用CRC码(cyclic Redundancy Code)检测读出数据是否有错。CRC码有很强的检错功能,但没有开发它的纠错功能,因此只用它来检错。
---

看来我的认识错误。

【上篇】
【下篇】

抱歉!评论已关闭.