`

简单实现TCP下的大文件高效传输

阅读更多
原帖地址:http://www.cnblogs.com/smark/p/3143597.html

在TCP下进行大文件传输不象小文件那样直接打包个BUFFER发送出去,因为文件比较大所以不可能把文件读到一个BUFFER发送出去.主要有些文件的大小可能是1G,2G或更大,分配这么大的BUFFER对内存来说显然是不现实的事情;针对服务端的设计来说就更需要严紧些,BUFFER大小的限制也是变得很重要.下面介绍使用Beetle简单地实现大文件在TCP的传应用.


协议制定


既然需要把文件分块来处理,那在TCP传输的过程需要制定一些协议来规范数据有效性,数据协议主要有三个:告诉服务器需要上传文件,文件块上传和返回每个环节处理的结果.


1)上传文件指令




public class Upload:ObjectMessage
{
public string FileMD5
{
get;
set;
}

public string FileName
{
get;
set;
}

public long FileSize
{
get;
set;
}

public override void FromProtocolData(HttpData httpbase)
{
FileName
= httpbase[CONSTVALUE.HEADER_NAME];
FileMD5
= httpbase[CONSTVALUE.HEADER_MD5];
FileSize
= long.Parse(httpbase[CONSTVALUE.HEADER_FILESIZE]);
}

protected override void OnDisposed()
{

}

protected override void OnToProtocolData(HttpData httpbase)
{
httpbase.Command
= CONSTVALUE.COMMAND_UPLOAD;
httpbase[CONSTVALUE.HEADER_MD5]
= FileMD5;
httpbase[CONSTVALUE.HEADER_NAME]
= FileName;
httpbase[CONSTVALUE.HEADER_FILESIZE]
= FileSize.ToString();
}
}



2)上传文件块指令




public class UploadData:ObjectMessage
{

public string FileMD5
{
get;
set;
}

public Beetle.ByteArraySegment Data
{
get;
set;
}

public override void FromProtocolData(HttpData httpbase)
{
FileMD5
= httpbase[CONSTVALUE.HEADER_MD5];
Data
= httpbase.Content;
}

protected override void OnDisposed()
{
if (Data != null)
{
FileTransferPackage.BufferPool.Push(Data);
Data
= null;
}
}

protected override void OnToProtocolData(HttpData httpbase)
{
httpbase.Command
= CONSTVALUE.COMMAND_UPLOAD_DATA;
httpbase[CONSTVALUE.HEADER_MD5]
= FileMD5;
httpbase.Content
= Data;
}
}



3)返回值指令




public class Result :ObjectMessage
{
public string FileMD5
{
get;
set;
}

public bool Error
{
get;
set;
}

public string ErrorDetail
{
get;
set;
}

public override void FromProtocolData(HttpData httpbase)
{
ErrorDetail
= httpbase[CONSTVALUE.HEADER_STATUS_DETAIL];
Error
= httpbase[CONSTVALUE.HEADER_STATUS] == CONSTVALUE.VALUE_SUCCESS;
FileMD5
= httpbase[CONSTVALUE.HEADER_MD5];
}

protected override void OnDisposed()
{

}

protected override void OnToProtocolData(HttpData httpbase)
{
httpbase.Command
= CONSTVALUE.COMMAND_RESULT;
if (Error)
{
httpbase[CONSTVALUE.HEADER_STATUS]
= CONSTVALUE.VALUE_SUCCESS;
}
else
{
httpbase[CONSTVALUE.HEADER_STATUS]
= CONSTVALUE.VALUE_ERROR;
}
httpbase[CONSTVALUE.HEADER_STATUS_DETAIL]
= ErrorDetail;
httpbase[CONSTVALUE.HEADER_MD5]
= FileMD5;
}
}



ObjectMessage是Beetle一个简化HTTP协议的扩展对象,它提供自定义Header和Body等功能.


文件读写器


既然需要处理文件块,那提供一些简单的文件块读取和写入方法是比较重要的.它不仅从设计解决功能的偶合度,还可以方便今后的利用.


1)UploadReader 




public class UploadReader : IDisposable
{
public UploadReader(string file)
{

mStream
= System.IO.File.OpenRead(file);
StringBuilder sb
= new StringBuilder();
MD5 md5Hasher
= MD5.Create();
foreach (Byte b in md5Hasher.ComputeHash(mStream))
sb.Append(b.ToString(
"x2").ToLower());
FileMD5
= sb.ToString();
mStream.Position
= 0;
FileSize
= mStream.Length;
FileName
= System.IO.Path.GetFileName(file);

}

private System.IO.FileStream mStream = null;

public string FileName
{
get;
set;
}

public long LastReadLength
{
get;
set;
}

public long ReadLength
{
get;
set;
}

public long FileSize
{
get;
set;
}

public string FileMD5
{
get;
set;
}

public bool Completed
{
get
{
return mStream != null && ReadLength == mStream.Length;
}
}

public void Close()
{
if (mStream != null)
{
mStream.Close();
mStream.Dispose();
}
}

public void Reset()
{
mStream.Position
= 0;
LastReadLength
= 0;
ReadLength
= 0;
}

public void Read(ByteArraySegment segment)
{
int loads = mStream.Read(segment.Array, 0, FileTransferPackage.BUFFER_SIZE);
segment.SetInfo(
0, loads);
ReadLength
+= loads;
}

public void Dispose()
{
mStream.Dispose();
}

public override string ToString()
{
string value= string.Format("{0}(MD5:{4})\r\n\r\n[{1}/{2}({3}/秒)]",FileName,ReadLength,FileSize,ReadLength-LastReadLength,FileMD5);
if (!Completed)
{
LastReadLength
= ReadLength;
}
return value;
}
}



UploadReader的功能主要是把文件流读取到指定大小的Buffer中,并提供方法获取当前的读取情况


2)UploadWriter




public class UploadWriter
{
public UploadWriter(string rootPath, string filename,string fileMD5,long size)
{
mFullName
= rootPath + filename;
FileName
= filename;
FileMD5
= fileMD5;
Size
= size;
}

private string mFullName;

private System.IO.FileStream mStream;

public System.IO.FileStream Stream
{
get
{
if (mStream == null)
{
mStream
= System.IO.File.Create(mFullName+".up");
}
return mStream;
}
}

public long WriteLength
{
get;
set;
}

public long LastWriteLength
{
get;
set;
}

public long Size
{
get;
set;
}

public string FileName
{
get;
set;
}

public string FileMD5
{
get;
set;
}

public bool Write(ByteArraySegment segment)
{
Stream.Write(segment.Array,
0, segment.Count);
WriteLength
+= segment.Count;
Stream.Flush();
if (WriteLength == Size)
{
Stream.Close();
if (System.IO.File.Exists(mFullName))
System.IO.File.Delete(mFullName);
System.IO.File.Move(mFullName
+ ".up", mFullName);
return true;
}
return false;
}
}



UploadWriter的功能主要是把文件写入到临时文件中,写入完成后再更改相应的名称,为了方便查询同样也提供了一些写入情况信息.


服务端代码


 如果有了解过Beetle的服务端制定的话,那服务端的实现是非常简单的,只需要写一个对象承继ServerBase并实现数据接收方法处理即可以,接收的数据会会自动转换成之前定义的消息对象,而服务端内部处理的细节是完全不用关心.



protected override void OnMessageReceive(Beetle.PacketRecieveMessagerArgs e)
{
base.OnMessageReceive(e);
if (e.Message is Protocol.Upload)
{
OnUpload(e.Channel, e.Message
as Protocol.Upload);
}
else if (e.Message is Protocol.UploadData)
{
OnUploadData(e.Channel, e.Message
as Protocol.UploadData);
}
}

private Protocol.Result GetErrorResult(string detail)
{
Protocol.Result result
= new Protocol.Result();
result.Error
= true;
result.ErrorDetail
= detail;
return result;
}

private void OnUpload(Beetle.TcpChannel channel, Protocol.Upload e)
{
Protocol.Result result;
if (mTask[e.FileMD5] != null)
{
result
= GetErrorResult( "该文件正在上传任务中!");
channel.Send(result);
return;
}
UploadWriter writer
= new UploadWriter(mRootPath, e.FileName, e.FileMD5, e.FileSize);
lock (mTask)
{
mTask[e.FileMD5]
= writer;
}
result
= new Protocol.Result();
channel.Send(result);
}

private void OnUploadData(Beetle.TcpChannel channel, Protocol.UploadData e)
{
using (e)
{
Protocol.Result result;
UploadWriter writer
= (UploadWriter)mTask[e.FileMD5];
if (writer == null)
{
result
= GetErrorResult("上传任务不存在!");
channel.Send(result);
return;
}
if (writer.Write(e.Data))
{
lock (mTask)
{
mTask.Remove(e.FileMD5);
}
}
result
= new Protocol.Result();
result.FileMD5
= writer.FileMD5;
channel.Send(result);
}
}


当接收到客户求上传请求后会建立对应MD5的文件写入器,后面文件块的上传写入相关对象即可.


客户端代码


 Beetle对于Client的支持也是非常简单方便,只需要定义一个TcpChannel直接发送定义的对象消息并获取服务器端返回的消息即可.




 1 private void OnUpload(object state)
2 {
3 Lib.UploadReader reader = (Lib.UploadReader)state;
4 try
5 {
6 IsUpload = true;
7 Lib.Protocol.Upload upload = new Lib.Protocol.Upload();
8 upload.FileMD5 = reader.FileMD5;
9 upload.FileName = reader.FileName;
10 upload.FileSize = reader.FileSize;
11 Lib.Protocol.Result result = mClient.Send<Lib.Protocol.Result>(upload);
12 if (result.Error)
13 {
14 mLastError = result.ErrorDetail;
15 return;
16 }
17 while (!reader.Completed)
18 {
19 mLastError = "文件上传中...";
20 Lib.Protocol.UploadData data = new Lib.Protocol.UploadData();
21 data.Data = Lib.FileTransferPackage.BufferPool.Pop();
22 data.FileMD5 = reader.FileMD5;
23 reader.Read(data.Data);
24 result = mClient.Send<Lib.Protocol.Result>(data);
25 if (result.Error)
26 {
27 mLastError = result.ErrorDetail;
28 return;
29 }
30 }
31 mLastError = "文件上传完成!";
32
33 }
34 catch (Exception e_)
35 {
36 mLastError = e_.Message;
37 }
38 mReader.Reset();
39 IsUpload = false;
40
41 }



整个过程只需要一个方法却可完成,首先把需要上传的文件信息发送到服务器,当服务器确认后不停地把文件块信息输送到服务端即可.


使用测试



下载代码


FileTransfer.Lib.rar (644.64 kb)

本文链接

分享到:
评论

相关推荐

    TCP实现的批量大文件传输

    TCP实现的批量大文件传输的C++库,一对多的模型 发送端: 外部调用只需要将文件路径传入,自己去读文件发送,发送端可以指定channel,ip,port,发送时,指定channel推送文件路径即可,挺好用的 接收端: 只需要初始化...

    HPSocket高效传输,自动分包组包

    开源一份HPSocket的tcp的高效传输方案,自动组包分包,我精简了HPSocket4C.dll文件删除了所有的代理,http,udp等等一大堆的东西,dll文件又经过upx压缩仅80kb大小,只保留tcp pack部分。pack本来就是可靠传输,一般...

    计算机网络课程设计 ftp文件传输系统 源代码

    该协议是Internet文件传送的基础,它由一系列规格说明文档组成,目标是提高文件的共享性,提供非直接使用远程计算机,使存储介质对用户透明和可靠高效地传送数据。简单的说,FTP就是完成两台计算机之间的拷贝,从...

    LabView与SMART网络TCP通讯(使用LabVIEW内部自带VI),搭建通讯架构,实现数据的传输,可根据需要自由扩充,内

    LabView与SMART网络TCP通讯(使用LabVIEW内部自带VI),搭建通讯架构,实现数据的传输,可根据需要自由扩充,内附使用说明。 文件为源程序,未设密码,可用于学习 借鉴用。 通过利用LabVIEW内部自带的VI,可以...

    局域网文件传输系统.doc

    鉴于局域网有如上优点,开发一个方便快捷的局域网文件传输系统是很有意义的,它 在文件传输方面的高效准确将会提高企业的办事效率,为企业节省开支,为家庭用户提 供方便。 关键词 TCP/IP协议;C/S结构;Windows ...

    毕设源码-VB点对点聊天文件传输系统设计(源代码+系统).rar

    系统采用客户端-服务器架构,通过TCP协议进行通信,保证了数据传输的稳定性和高效性。 主要功能特点: 1. **实时聊天**:用户可以在聊天界面上发送和接收文本消息,实现即时交流。 2. **文件传输**:支持单个或...

    蚂蚁快传AntM3.1.0.13 使用手册

     传输高效,传输效率远大于Serv-U、Vpfs等FTP文件服务器  自动断开无效连接  TCP支持断点续传  支持超大文件传输,最大文件规模为264(18446744073709551616约16384P = 16777216T = 17179869184G)

    fdt:FDT是高效数据传输的应用程序,它能够以磁盘速度在广域网(使用标准TCP)上进行读写。 它是用Java编写的,可以在所有主要平台上运行,并且易于使用。 FDT基于异步,灵活的多线程系统,并使用Java NIO库的功能

    FDT是高效数据传输的应用程序,它能够以磁盘速度在广域网(使用标准TCP)上进行读写。 它是用Java编写的,可以在所有主要平台上运行,并且易于使用。 FDT基于异步,灵活的多线程系统,并且正在使用Java NIO库的功能...

    网编小项目:FTP文件传输服务器

    该项目是一个FTP(文件传输协议)服务器,允许用户通过网络连接并在服务器和客户端之间传输文件。 项目旨在实现高效的文件传输,同时提供基本的文件管理功能。 支持多客户端 多线程并发。

    蚂蚁快传AntM3.1.0.13

    多协议支持,功能强大、配置灵活、性能稳定、传输高效。 AntM主要功能是实现海量文件从一个终端向另一个终端实时、批量、全自动的迁移。 Ø 主要特征 l 支持FTP、TCP协议。 l 多线程并发传输 l IP地址过滤和...

    AntM3.1.1.3

    l 多线程并发传输 l IP地址过滤和屏蔽 l 基于用户验证的传输安全管理 l 多种发送文件过滤方式 l 多种远程文件组织方式 l 网络因逻辑错误、网络故障等原因中断后可自动重连传输 l AntM的Tcp Server传输效率大于Serv-...

    AntM3.1.1.6蚂蚁快传

    l 多线程并发传输 l IP地址过滤和屏蔽 l 基于用户验证的传输安全管理 l 多种发送文件过滤方式 l 多种远程文件组织方式 l 网络因逻辑错误、网络故障等原因中断后可自动重连传输 l AntM的Tcp Server传输效率大于Serv-...

    oDrop:oDrop,一种用于服务器和家庭环境的快速高效的跨平台文件传输软件

    oDrop是跨平台的LAN文件传输软件,可以在计算机之间高效地传输文件。oDrop在没有GUI的环境中很有用。 oDrop和其他文件传输软件有什么区别 oDrops命令简单易记,这是创建oDrop时的首要任务之一。 特征 使用udp4查找...

    HTTP协议(HyperText Transfer Protocol,超文本传输协议)

    我们知道,Internet的基本协议是TCP/IP协议,然而在TCP/IP模型最上层的是应用层(Applicationlayer),它包含所有高层的协议。高层协议有:文件传输协议FTP、电子邮件传输协议SMTP、域名系统服务DNS、网络新闻传输协议...

    Linux网络编程,包括tcp/upd,select/poll/epoll/pdf

    其中select/poll/epoll都是常用的多路复用技术,它们可以同时监视多个文件描述符,实现高效的I/O复用。 总之,Linux网络编程是一项重要的技能,它涉及到网络通信的基本原理以及多路复用技术的使用,对于开发网络...

    通信与网络中的基于Linux操作系统下的TCP/IP网络通信研究与应用

    还内含了TCP/IP网络协议,很适合在服务器领域使用,而服务器主要用途之一就是进行网络通信,随着计算机办公自动化处理技术的应用与推广,网络的不断普及,传统的纸张式文件传输方式已经不再适合发展的需要,人们更...

    VB GIF_LZW图像压缩算法实现桌面传输

    内容索引:VB源码,网络相关,文件传输 VB利用了GIF_LZW算法实现网络图片传输,也就是Windows XP系统自带的远程桌面登录后的功能,程序仍然采用稳定性好的TCP协议及字节数据流进行传输,减少了编码时间,另外使用GIF-...

    java源码包---java 源码 大量 实例

    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

Global site tag (gtag.js) - Google Analytics