艺萌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代表,如何从小白成为技术专家?点击了解活动详情 作者 | 庄进发 编辑 | 迷鹿 庄进发,信息安全部后台开发工程师,主要负责 ...
随机推荐
- 初识NodeJS,一个基于GoogleV8引擎的Javascript运行环境
思考 首先我们来思考一个问题:我们都知道几乎所有现代主流浏览器都全面支持了ECMAScript 5.1版标准,而JavaScript的标准是ECMAScript.那么我们就容易认为JavaScript ...
- hive的使用02
1.hive的交互方式 1.1 bin/hive 进入hive交互命令行环境 1.2 bin/hive -e 'select * from hive.student;' (可以通过 > 将结果写 ...
- CSS学习心得
CSS 指层叠样式表 (Cascading Style Sheets) 样式定义如何显示 HTML 元素 样式通常存储在样式表中 把样式添加到 HTML 4.0 中,是为了解决内容与表现分离的问题 外 ...
- ChartControl 折线图 柱状图
添加折线图(柱状图) 拖动ChartControl到Form上 在Series Collection中添加Line(或Bar) DevExpress.XtraCharts.Series series1 ...
- IE11 iframe alternative
<OBJECT classid=clsid:8856F961-340A-11D0-A96B-00C04FD705A2> <PARAM NAME=Location VALUE=http ...
- docker tomcat7 dubbo-admin monitor
docker run --name=dubbo_admin9201 -tid -p : -v /home/dubbo/admin:/usr/local/tomcat7/webapps/ROOT cen ...
- VC++常用数据类型转化
char* 转换成 LPCTSTR const char* dibFileName; , , dibFileName, -, NULL, ); wchar_t *wide = new wchar_t[ ...
- [linux] scp无密码拷贝
源服务器为s,ip为111.111.111.112. 目标服务器为d, ip为111.111.111.111 1>在源服务器新建用户 test_s, useradd test_s -g user ...
- iBatis框架基本使用
iBatis框架是Java持久层开发框架,说白了就是前人写了一部分代码(针对数据库操作),我们要做的就是再次开发,拿来框架直接使用. 我们自己开发时,dao层的sql语句都是写死在程序中的,如果查询条 ...
- Wiki设置
在Wiki安装完成后,就wiki会提示下载LocalSettings.php文件,这是wiki的设置文件,当我们要对wiki进行设置的时候,就需要用到这个文件. 下面对常用的操作设置做简要讲解: —— ...