您的位置:首页 > 其它

利用Socket传输文件时,接收方判断文件末尾的方法

2010-03-17 10:59 316 查看
Socket传输文件。一般采用文件流的方式。无论要传输的文件什么样的类型,它都是文件,我们都可以将它看成是文本文件。尽管用记事本打开后它有可能乱码。这一种意识很重要,因为这能有效地降低搭建程序的难度,简化问题的复杂性。



既然把文件都看成是文本文件了,那么就很容易理解要传输的文件是由一个一个的“字符”(Char)构成,因此,为了加快传输,便想起了使用缓冲式发送和接收。方法就是声明一个缓冲池,其实就是一个char类型的数组。比方说是512字节的缓冲池,那我就可以这样声明



Const

BufferSize=512;



Buffer:array[0...BufferSize-1] of char;



然后声明一个文件流



Var

FS:TFileStream;



创建文件流



FS:=TFileStream.Create(FileName,Mode);



下面很重要,作为发送方 我要知道我要发送多少内容,已经发送了多少内容,怎么样将一个文件分片,即将一个文件分割成若干个小于等于缓冲池大小的部分。

那就要考虑两种情况了。第一种,这个文件比缓冲池小,那么就一下把它传完吧;第二种,这个文件大于缓冲池,那么我需要一个“永真”的循环,然后一次读取一个缓冲池大小的字符,然后发送,这时候看看还有多少字节没有发送。当剩余的字节仍然大于缓冲池大小,回到第二种情况,如果剩余的字节小于缓冲池,回到第一种情况,将这些剩余字节一下传完,然后跳出永真循环。



FS:=TFileStream.Create(FileName,Mode);//创建文件流 载入相关文件
if FS.Size<>0 then //大前提 必须是有数据才传输
begin
LeftSize:=FS.Size; //还没有开始传输 因此剩余大小初始化为文件流的大小
while True do
begin
if LeftSize=0 then //如果剩余的大小为0 说明已经发送完毕 跳出循环
begin
Break;
end
else
begin
if LeftSize<BufferSize then //还有剩余数据 看看这些数据够不够缓冲池的大小 如果小于
begin
SendSize:=LeftSize; //说明此次传输的字符不构成一整个缓冲池 那么这一次发送字节数设置为剩余字节数
end
else
begin
Sendsize:=BufferSize;//剩余数据大于了缓冲池大小 那么这次发送数据的大小就设置为缓冲池大小
end;
FS.ReadBuffer(Buff,SendSize);//从文件流中读取本次发送字节数个字符,将这些字符放在Buff缓冲池中
ServerSocket.Socket.Connections[0].SendBuf(Buff,SendSize);//将缓冲池中的数据发送出去 发送的字节数是由上一步计算得来
LeftSize:=LeftSize-SendSize;//将剩余字节数减去本次发送的数量 以备下次循环时判断
Sleep(10);//暂停发送10ms 给接收方一个处理的时间
end;
end;
end;
FS.Free;//释放文件流 释放内存



在 李存斌 汪兵 编著的《Delphi 深度编程及其项目应用开发》 一书中,209页有这么一段话



//当接收到的数据不等于bufSize,代表接收的屏幕图像的最后一个数据,
//否则,代表还没有接收完,继续相服务器端发送'show‘指令,继续获取数据



我不太同意这种判断方法
假设一种极端的情况,我要传输的文件大小是2048个字节,缓冲池设置为512个字节,那么当接收方第四次接收完数据后,整个传输过程就结束了,而这四次传输中,每一次都满足所谓的“没有接收完”的条件。因此这种判定方法并不健全。



以下我提出了两种方法解决这个问题



第一种:该BufferSize。这种方法也许编程老手看了之后会非常惊讶!什么?改BufferSize?那你怎么同步发送者与接收者!毕竟要使双方的BufferSize一致才行啊!是的,没错。具体做法是这样的。发送方先设置一个初始的BufferSize,比方说512字节。然后再计算一下要发送的数据总大小是不是该缓冲池大小的整数倍。如果是,就满足了刚才提出的极端条件,那么我就在512附近(比方说513,514)找一个数,看看能不能被整除,肯定能找到一个数不能被总大小整除的。好的,记下这个数值,然后用一串自己定义的特殊字符携带该数值先发送给接收方(该数据的大小要小于当前的BufferSize)。接收方一受到数据后发现,该数据满足自定义的格式,那么就提取出里面包含的数值,然后重新设置BufferSize。以后的传输,发送方和接收方就都采用这个新的BufferSize。至于判断文件有没有传完,那就再用上面的判断方法就是了。



第二种:也是先计算要传输的数据大小是不是缓冲池大小的整数倍。如果是,那么就在原始数据后添加一段非常特殊的自定义的数据(这段数据大小不要超过缓冲池大小),在所有数据都发送完毕之后,再将此数据发送给接收方。接收方收到之后,发现该数据大小不等于缓冲池大小,而且满足了特定的格式,那么忽略此条数据,将以前收到的数据直接从文件流中提取,另存为文件。



当然了,还有人会提出,那我要是要传输的数据里正好包含我所定义的特殊数据怎么办?呵呵,怎么说呢,其实很多时候都是有概率在里面的,比起文件的大小等于缓冲池的整数倍,特殊数据与要传输的数据一样的概率还是要小很多的。如果你还担心,那么就把缓冲区的初始大小设置得大一些,比方说1024字节。这样,在这1024字节中,内容相同的概率就更小了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐