艺萌TCP文件上传下载及自动更新系统介绍(TCP文件传输)(一)
艺萌TCP文件上传下载及自动更新系统介绍(TCP文件传输)
该系统基于开源的networkComms通讯框架,此通讯框架以前是收费的,目前已经免费并开元,作者是英国的,开发时间5年多,框架很稳定。
项目地址:http://www.51aspx.com/code/MSDCArtMengFileUpload
咨询qq:286275658
演示程序下载地址:http://pan.baidu.com/s/1geVfmcr
服务器端运行效果图:

服务器端配置文件:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="DirectoryPath" value="D:\"/> //客户端上传的文件的保存路径
<add key="IPAddress" value="127.0.0.1"/> //服务器端的IP 需要修改真实的IP
<add key="Port" value="6006"/> //监听的端口号
</appSettings>
</configuration>
服务器端接收文件的部分代码:
// 处理文件数据
private void IncomingPartialFileData(PacketHeader header, Connection connection, byte[] data)
{
try
{
SendInfo info = null;
//每次都创建一个对 ReceivedFile对象的引用 引用receivedFilesDict字典中的对象 引用完成后设定为Null
IReceiveFile receivedFile = null;
//Perform this in a thread safe way
lock (syncLocker)
{
//获取数据包的顺序号
long sequenceNumber = header.GetOption(PacketHeaderLongItems.PacketSequenceNumber);
//如果数据信息字典包含 "连接信息" 和 "包顺序号"
if (incomingDataInfoCache.ContainsKey(connection.ConnectionInfo) && incomingDataInfoCache[connection.ConnectionInfo].ContainsKey(sequenceNumber))
{
//根据顺序号,获取相关SendInfo记录
info = incomingDataInfoCache[connection.ConnectionInfo][sequenceNumber];
//从信息记录字典中删除相关记录
incomingDataInfoCache[connection.ConnectionInfo].Remove(sequenceNumber);
if (!recvManager.ContainsFileID(info.FileID))
{
recvManager.AddFile(info.FileID, info.Filename, info.FilePath, connection.ConnectionInfo, info.TotalBytes);
}
receivedFile = recvManager.GetFile(info.FileID);
}
else
{
//We do not yet have the associated SendInfo so we just add the data to the cache
//如果不包含顺序号,也不包含相关"连接信息",添加相关连接信息
if (!incomingDataCache.ContainsKey(connection.ConnectionInfo))
incomingDataCache.Add(connection.ConnectionInfo, new Dictionary<long, byte[]>());
//在数据字典中添加相关"顺序号"的信息
incomingDataCache[connection.ConnectionInfo].Add(sequenceNumber, data);
}
}
if (info != null && receivedFile != null && !receivedFile.IsCompleted)
{
receivedFile.AddData(info.BytesStart, , data.Length, data);
receivedFile = null;
data = null;
}
else if (info == null ^ receivedFile == null)
throw new Exception("Either both are null or both are set. Info is " + (info == null ? "null." : "set.") + " File is " + (receivedFile == null ? "null." : "set.") + " File is " + (receivedFile.IsCompleted ? "completed." : "not completed."));
}
catch (Exception ex)
{
NetworkHelper.LogTools.LogException(ex, "IncomingPartialFileDataError");
}
}
IncomingPartialFileData
private void IncomingPartialFileDataInfo(PacketHeader header, Connection connection, SendInfo info)
{
try
{
byte[] data = null;
//每次都创建一个对 ReceivedFile对象的引用 引用receivedFilesDict字典中的对象 引用完成后设定为Null
IReceiveFile file = null;
lock (syncLocker)
{
//从 SendInfo类中获取相应数据类的信息号 以便可以对应。
long sequenceNumber = info.PacketSequenceNumber;
if (incomingDataCache.ContainsKey(connection.ConnectionInfo) && incomingDataCache[connection.ConnectionInfo].ContainsKey(sequenceNumber))
{
//从字典中获取数据
data = incomingDataCache[connection.ConnectionInfo][sequenceNumber];
//删除字典中的数据
incomingDataCache[connection.ConnectionInfo].Remove(sequenceNumber);
if (!recvManager.ContainsFileID(info.FileID))
{
recvManager.AddFile(info.FileID, info.Filename, info.FilePath, connection.ConnectionInfo, info.TotalBytes);
}
file = recvManager.GetFile(info.FileID);
}
else
{
if (!incomingDataInfoCache.ContainsKey(connection.ConnectionInfo))
incomingDataInfoCache.Add(connection.ConnectionInfo, new Dictionary<long, SendInfo>());
incomingDataInfoCache[connection.ConnectionInfo].Add(sequenceNumber, info);
}
}
if (data != null && file != null && !file.IsCompleted)
{
file.AddData(info.BytesStart, , data.Length, data);
//Perform a little clean-up
file = null;
data = null;
}
else if (data == null ^ file == null)
throw new Exception("Either both are null or both are set. Data is " + (data == null ? "null." : "set.") + " File is " + (file == null ? "null." : "set.") + " File is " + (file.IsCompleted ? "completed." : "not completed."));
}
catch (Exception ex)
{
NetworkHelper.LogTools.LogException(ex, "IncomingPartialFileDataInfo");
}
}
IncomingPartialFileDataInfo
.



部分代码:
public class SendFile
{
//传输过程 事件
public event EventHandler<FTProgressEventArgs> FileTransProgress;
//传输完成 事件
public event EventHandler<FTCompleteEventArgs> FileTransCompleted;
//传输中断 事件
public event EventHandler<FTDisruptEventArgs> FileTransDisruptted;
//取消文件的发送
private volatile bool canceled = false;
//传输失败的原因
private FileTransFailReason fileTransDisrupttedType = FileTransFailReason.Error;
public string FilePath { get; private set; }
private Connection tcpConn;
// 收发参数
private SendReceiveOptions sendFileOptions = null;
//文件ID 用于管理文件 和文件的发送 取消发送相关
private string fileID;
public string FileID
{
get { return fileID; }
set { fileID = value; }
}
//文件传输后存储的路径
private string destFilePath;
public string DestFilepath
{
get { return destFilePath; }
set { destFilePath = value; }
}
// 文件的字节大小
public long SizeBytes { get; private set; }
// 已发送的大小
public long SentBytes { get; private set; }
//已经完成的百分比
public double CompletedPercent
{
get { return (double)SentBytes / SizeBytes; }
set { throw new Exception("An attempt to modify read-only value."); }
}
// 是否完成
public bool IsCompleted
{
get { return SentBytes == SizeBytes; }
}
// 同步锁
object SyncRoot = new object();
/// <summary>
/// 创建一个文件发送实例
/// </summary>
/// <param name="filename">文件名称</param>
/// <param name="filePath">文件本地路径</param>
/// <param name="destFilePath">文件在服务器上的相对路径</param>
public SendFile(string fileID, string filePath, string destFilePath,Connection conn)
{
//文件ID
this.fileID = fileID;
this.FilePath = filePath;
this.destFilePath = destFilePath;
this.sendFileOptions = new SendReceiveOptions(DPSManager.GetDataSerializer<ProtobufSerializer>(), null, null);
this.sendFileOptions.ReceiveHandlePriority = NetworkCommsDotNet.Tools.QueueItemPriority.Highest;
this.tcpConn = conn;
}
//异步发送文件
public void NowSendFile()
{
new Action(this.StartSendFile).BeginInvoke(null, null);
}
//发送文件
public void StartSendFile()
{
FileStream stream = null;
try
{
//根据选择的文件创建一个文件流
stream = new FileStream(this.FilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
//包装成线程安全的数据流
StreamTools.ThreadSafeStream safeStream = new StreamTools.ThreadSafeStream(stream);
//获取不包含路径信息的文件名
string shortFileName = System.IO.Path.GetFileName(FilePath);
//根据参数中设定的值来角色发送的数据包的大小 可以根据您的网络环境指定
;
this.SizeBytes = stream.Length;
;
while ((totalBytesSent < stream.Length) && !this.canceled)
{
//剩下的字节数 如果 大于 指定的字节数(sendChunkSizeBytes),则发送指定的字节数 否则 发送剩下的字节数
long bytesToSend = (totalBytesSent + sendChunkSizeBytes < stream.Length ? sendChunkSizeBytes : stream.Length - totalBytesSent);
StreamTools.StreamSendWrapper streamWrapper = new StreamTools.StreamSendWrapper(safeStream, totalBytesSent, bytesToSend);
//我们希望记录包的顺序号
long packetSequenceNumber;
//发送文件的数据部分
tcpConn.SendObject("PartialFileData", streamWrapper, sendFileOptions, out packetSequenceNumber);
//把包的顺序号记录在 SendInfo类中。 destFilePath 是文件在服务器端保存的路径(相对路径)
tcpConn.SendObject("PartialFileDataInfo", new SendInfo(fileID, shortFileName, destFilePath, stream.Length, totalBytesSent, packetSequenceNumber), sendFileOptions);
totalBytesSent += bytesToSend;
//更新已经发送的字节的属性
SentBytes += bytesToSend;
FileTransProgress.Raise(this, new FTProgressEventArgs(FileID, SizeBytes, totalBytesSent));
//发送文件片段后应休息一定的时间 能有效的降低系统cpu
if (! this.canceled )
{
Thread.Sleep();
}
}
if (!this.canceled)
{
//触发文件传输完成事件
FileTransCompleted.Raise(this, new FTCompleteEventArgs(fileID));
}
else
{
//否则触发文件中断事件
FileTransDisruptted.Raise(this, new FTDisruptEventArgs(FileID, FileTransFailReason.Error));
}
}
catch (CommunicationException)
{
//触发文件中断事件
FileTransDisruptted.Raise(this, new FTDisruptEventArgs(FileID, FileTransFailReason.Error));
}
catch (Exception ex)
{
//触发文件中断事件
FileTransDisruptted.Raise(this, new FTDisruptEventArgs(FileID, FileTransFailReason.Error));
}
finally
{
if (stream != null)
{
stream.Close();
}
}
}
//取消文件的发送
public void Cancel(FileTransFailReason transFileReason)
{
this.canceled = true;
this.fileTransDisrupttedType = transFileReason;
//给服务器发一个消息,说明文件发送中断 传送fileID给服务器端即可
FileContract filecontract = new FileContract(this.fileID, "FileName", "Comment");
//通知对方 让对方取消当期文件的接收 并清理相关缓存
tcpConn.SendObject("CancelSendFile", filecontract);
}
}
SendFile
客户端介绍了如何上传下载文件,如何启用自动升级程序


上传文件:
private void button1_Click(object sender, EventArgs e)
{
//获取要上传的文件的本地地址
string filePath = GetFileToOpen("上传文件");
//新建一个文件ID
string fileID = FileIDCreator.GetNextFileID(NetworkCommsDotNet.NetworkComms.NetworkIdentifier.ToString());
//定义文件在服务器的保存位置(相对目录)
string destFilePath = itemID + @"\" + Path.GetFileName(filePath);
//把文件添加到文件发送管理器中
sendFileDict.AddSendFile(fileID, filePath, destFilePath,AppOutter.TcpConn);
}
下载文件:
openFlag = false;
)
{
string fileName = (listBox1.SelectedItem as FileDetail).Name;
long fileSize = (listBox1.SelectedItem as FileDetail).Size;
ulong theFileSize = Convert.ToUInt32(fileSize);
//获取当前文件扩展名
string extentName = Path.GetExtension(fileName);
string savePath = FileHelper.GetPathToSave("选择保存路径", fileName, null);
if (savePath != null)
{
//如果在弹出窗口中,用户改动了名字,需要手动加上扩展名
if (!savePath.EndsWith(extentName))
{
savePath = savePath + extentName;
}
//取得目录所在的相对位置 如: 201011\123456\文件.txt
string fileUri = itemID + @"\" + fileName;
try
{
FileInfoContract contract = new FileInfoContract(savePath, fileUri);
AppOutter.TcpConn.SendObject("DownloadFile", contract);
}
catch (Exception ee)
{
MessageBox.Show(ee.Message);
}
}
}
上传界面:

文章地址:www.cnblogs.com/networkcomms
艺萌TCP文件上传下载及自动更新系统介绍(TCP文件传输)(一)的更多相关文章
- 艺萌文件上传下载及自动更新系统(基于networkComms开源TCP通信框架)
1.艺萌文件上传下载及自动更新系统,基于Winform技术,采用CS架构,开发工具为vs2010,.net2.0版本(可以很容易升级为3.5和4.0版本)开发语言c#. 本系统主要帮助客户学习基于TC ...
- Android与Asp.Net Web服务器的文件上传下载BUG汇总[更新]
遇到的问题: 1.java.io.IOException: open failed: EINVAL (Invalid argument)异常,在模拟器中的sd卡创建文件夹和文件时报错 出错原因可能是: ...
- NetworkComms 文件上传下载和客户端自动升级(非开源)
演示程序下载地址:http://pan.baidu.com/s/1geVfmcr 淘宝地址:https://shop183793329.taobao.com 联系QQ号:3201175853 许可:购 ...
- Retrofit2文件上传下载及其进度显示
序 前面一篇文章介绍了Retrofit2的基本使用,这篇文章接着介绍使用Retrofit2实现文件上传和文件下载,以及上传下载过程中如何实现进度的显示. 文件上传 定义接口 1 2 3 @Multip ...
- JavaWeb 文件上传下载
1. 文件上传下载概述 1.1. 什么是文件上传下载 所谓文件上传下载就是将本地文件上传到服务器端,从服务器端下载文件到本地的过程.例如目前网站需要上传头像.上传下载图片或网盘等功能都是利用文件上传下 ...
- 转载:JavaWeb 文件上传下载
转自:https://www.cnblogs.com/aaron911/p/7797877.html 1. 文件上传下载概述 1.1. 什么是文件上传下载 所谓文件上传下载就是将本地文件上传到服务器端 ...
- iOS开发之结合asp.net webservice实现文件上传下载
iOS开发中会经常用到文件上传下载的功能,这篇文件将介绍一下使用asp.net webservice实现文件上传下载. 首先,让我们看下文件下载. 这里我们下载cnblogs上的一个zip文件.使用N ...
- HttpClient文件上传下载
1 HTTP HTTP 协议可能是如今 Internet 上使用得最多.最重要的协议了,越来越多的 Java 应用程序须要直接通过 HTTP 协议来訪问网络资源. 尽管在 JDK 的 java.net ...
- Nginx + Lua搭建文件上传下载服务
收录待用,修改转载已取得腾讯云授权 最新腾讯云技术公开课直播,提问腾讯W3C代表,如何从小白成为技术专家?点击了解活动详情 作者 | 庄进发 编辑 | 迷鹿 庄进发,信息安全部后台开发工程师,主要负责 ...
随机推荐
- mac攻略(七) -- 环境变量PATH分析
一.首先需要了解 1>mac 一般使用bash作为默认shell 2>Mac系统的环境变量,加载顺序为: 1.系统级别的 /etc/profile /etc/bashrc /etc/p ...
- javascript作用域链与原型链有联系吗?
一般来说,作用域链是针对变量的,js里面大的范围上来说,只有两种作用域,全局作用域和函数内部作用域,如果函数1里面又定义了函数2(一般都是匿名函数), 那么就有了这么一个作用域链全局作用域==> ...
- HDFS体系架构
Master-slaver结构,namenode是中心服务器维护着文件系统树和整个树内的文件目录, 负责整个数据集群的管理.datanode分布在不同的机架上,在客户端和namenode的调度下 存储 ...
- 关于editor网页编辑器ueditor.config.js 配置图片上传
最近公司项目在做一个门户网站,其中新闻和简介等部分使用到了ueditor编辑器,但是上级明确指示需要图片上传这个功能,这时却发现图片上传功能不能正常使用,上传时一直报错,网上收了好几个处理办法,都说的 ...
- Linux服务器的那些性能参数指标
Linux服务器的那些性能参数指标 一个基于Linux操作系统的服务器运行的同时,也会表征出各种各样参数信息.通常来说运维人员.系统管理员会对这些数据会极为敏感,但是这些参数对于开发者来说也十分重要, ...
- Ubuntu install g++
We can use two ways to install g++ on Ubuntu. 1. a. sudo apt-get install make gcc g++. b. sud ...
- 部署网站出现System.ServiceModel.Activation.HttpModule错误
1. 部署网站到IIS7.5,Window 2008的时候出现这个错误 2. 错误信息 Server Error in '/' Application. Could not load type 'Sy ...
- ie6、7下 text-indent 问题
text-indent属性 用于文字缩进,更多是用来隐藏文字.比如,一个logo标题,上面的问题很有艺术感,不得不把文字和背景组合成一张背景图(此处页面元素用a表示),但处于SEO方面的考虑,需要把a ...
- leveldb 学习。
1)大概浏览了leveldb文档的介绍.本想逐步看代码,想想还是自己先实现一个看看如何改进. 2)完成了一个非常丑陋的初版,但是还是比初初版有进步. 3)key value的数据库,不允许有key重复 ...
- iOS UIWebView重定向Cookie
// 1. 取出当前的cookies NSArray<NSHTTPCookie *> *cookies = [NSHTTPCookieStorage sharedHTTPCookieSto ...