利用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字节中,内容相同的概率就更小了。
既然把文件都看成是文本文件了,那么就很容易理解要传输的文件是由一个一个的“字符”(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字节中,内容相同的概率就更小了。
相关文章推荐
- 利用Socket实现多客户端传输对象和传输文件实现
- .Net网络通讯编程[利用Socket实现字串、文件、序列化对象传输]--类设计2
- .Net网络通讯编程[利用Socket实现字串、文件、序列化对象传输]--使用封装的网络服务2
- .Net网络通讯编程[利用Socket实现字串、文件、序列化对象传输]--类设计1[使用IE浏览本页]
- .Net网络通讯编程[利用Socket实现字串、文件、序列化对象传输]--使用封装的网络服务2[使用IE浏览本页]
- 利用socket传输图片或文件的代码实例
- 利用tar或dd在不同操作系统间传输文件的另类方法
- .Net网络通讯编程[利用Socket实现字串、文件、序列化对象传输]--类设计2[使用IE浏览本页]
- 利用Socket进行大文件传输
- 利用Socket.Send发送信息、Socket.SendFile传输文件
- java 利用socket传输文件
- Java利用socket传输文件
- .Net网络通讯编程[利用Socket实现字串、文件、序列化对象传输]--使用封装的网络服务3[聊天室][使用IE浏览本页]
- Net网络通讯编程[利用Socket实现字串、文件、序列化对象传输]--前面6篇博文全部源代码下载地址
- 利用Socket进行大文件传输
- .Net网络通讯编程[利用Socket实现字串、文件、序列化对象传输]--类设计1
- .Net网络通讯编程[利用Socket实现字串、文件、序列化对象传输]--使用封装的网络服务1
- .Net网络通讯编程[利用Socket实现字串、文件、序列化对象传输]--使用封装的网络服务4[聊天室][使用IE浏览本页]
- 利用secureCRT在windows和arm开发板之间传输文件的方法
- 利用tar或dd在不同操作系统间传输文件的另类方法