解决方案 »

  1.   

    第四步:客户端接收服务器发来的文件
    //处理文件数据 <2>
                NetworkComms.AppendGlobalIncomingPacketHandler<byte[]>("PartialFileData", IncomingPartialFileData);
                //处理文件信息 <3>
                NetworkComms.AppendGlobalIncomingPacketHandler<SendInfo>("PartialFileDataInfo", IncomingPartialFileDataInfo);private void IncomingPartialFileData(PacketHeader header, Connection connection, byte[] data)
            {
                try
                {
                    SendInfo info = null;
                    ReceivedFile file = null;                //Perform this in a thread safe way
                    lock (syncLocker)
                    {
                        //Extract the packet sequence number from the header
                        //The header can also user defined parameters
                        //获取数据包的顺序号
                        long sequenceNumber = header.GetOption(PacketHeaderLongItems.PacketSequenceNumber);                    //如果数据信息字典包含 "连接信息" 和  "包顺序号"                    if (incomingDataInfoCache.ContainsKey(connection.ConnectionInfo) && incomingDataInfoCache[connection.ConnectionInfo].ContainsKey(sequenceNumber))
                        {
                            //We have the associated SendInfo so we can add this data directly to the file
                            //根据顺序号,获取相关SendInfo记录
                            info = incomingDataInfoCache[connection.ConnectionInfo][sequenceNumber];
                            //从信息记录字典中删除相关记录
                            incomingDataInfoCache[connection.ConnectionInfo].Remove(sequenceNumber);
                            //Check to see if we have already initialised this file
                            //检查相关连接上的文件是否存在,如果不存在,则添加相关文件{ReceivedFile}
                            if (!receivedFiles.ContainsKey(info.FileID))
                            {
                                ReceivedFile receivedFile = new ReceivedFile(info.FileID, info.Filename, info.FilePath, connection.ConnectionInfo, info.TotalBytes);                            receivedFile.FileTransCompleted += new Action<string>(this.receivedFile_FileTransCompleted);                            receivedFiles.Add(info.FileID, receivedFile);
                              
                            }                        file = receivedFiles[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 we have everything we need we can add data to the ReceivedFile
                    if (info != null && file != null && !file.IsCompleted)
                    {
                        file.AddData(info.BytesStart, 0, data.Length, data);                    //Perform a little clean-up
                        file = null;
                        data = null;
                      
                    }
                    else if (info == null ^ file == null)
                        throw new Exception("Either both are null or both are set. Info is " + (info == null ? "null." : "set.") + " File is " + (file == null ? "null." : "set.") + " File is " + (file.IsCompleted ? "completed." : "not completed."));
                }
                catch (Exception ex)
                {
                    //If an exception occurs we write to the log window and also create an error file                
                }
            }IncomingPartialFileData
    private void IncomingPartialFileDataInfo(PacketHeader header, Connection connection, SendInfo info)
            {
                try
                {
                    byte[] data = null;
                    ReceivedFile file = null;                //Perform this in a thread safe way
                    lock (syncLocker)
                    {
                        //Extract the packet sequence number from the header
                        //The header can also user defined parameters
                        //从 SendInfo类中获取相应数据类的信息号 以便可以对应。
                        long sequenceNumber = info.PacketSequenceNumber;                    if (incomingDataCache.ContainsKey(connection.ConnectionInfo) && incomingDataCache[connection.ConnectionInfo].ContainsKey(sequenceNumber))
                        {
                            //We already have the associated data in the cache
                            data = incomingDataCache[connection.ConnectionInfo][sequenceNumber];
                            incomingDataCache[connection.ConnectionInfo].Remove(sequenceNumber);                        //Check to see if we have already initialised this file
                            if (!receivedFiles.ContainsKey(info.FileID))
                            {
                                ReceivedFile receivedFile = new ReceivedFile(info.FileID, info.Filename, info.FilePath, connection.ConnectionInfo, info.TotalBytes);
                                receivedFile.FileTransCompleted += new Action<string>(this.receivedFile_FileTransCompleted);
                                receivedFiles.Add(info.FileID, receivedFile);                        }                        file = receivedFiles[info.FileID];
                        }
                        else
                        {
                            //We do not yet have the necessary data corresponding with this SendInfo so we add the
                            //info to the cache
                            if (!incomingDataInfoCache.ContainsKey(connection.ConnectionInfo))
                                incomingDataInfoCache.Add(connection.ConnectionInfo, new Dictionary<long, SendInfo>());                        incomingDataInfoCache[connection.ConnectionInfo].Add(sequenceNumber, info);
                        }
                    }                //If we have everything we need we can add data to the ReceivedFile
                    if (data != null && file != null && !file.IsCompleted)
                    {
                        file.AddData(info.BytesStart, 0, 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)
                {
                     
                   
                }
            } IncomingPartialFileDataInfo
    MainActivity.cs中添加相应的字典变量
    //接收文件字典        Dictionary<string, ReceivedFile> receivedFiles = new Dictionary<string, ReceivedFile>();
            /// <summary>
            /// Incoming partial data cache. Keys are ConnectionInfo, PacketSequenceNumber. Value is partial packet data.
            /// </summary>
            Dictionary<ConnectionInfo, Dictionary<long, byte[]>> incomingDataCache = new Dictionary<ConnectionInfo, Dictionary<long, byte[]>>();        /// <summary>
            /// Incoming sendInfo cache. Keys are ConnectionInfo, PacketSequenceNumber. Value is sendInfo.
            /// </summary>
            Dictionary<ConnectionInfo, Dictionary<long, SendInfo>> incomingDataInfoCache = new Dictionary<ConnectionInfo, Dictionary<long, SendInfo>>();
      

  2.   

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;using Android.App;
    using Android.Content;
    using Android.OS;
    using Android.Runtime;
    using Android.Views;
    using Android.Widget;
    using System.IO;
    using NetworkCommsDotNet;
    using DPSBase;
    using Mobile.Entity;namespace Mobile.Client
    {
        public class ReceivedFile
        {
            //////传输过程
            ////public event Action<string, long, long> FileTransProgress;
            //////传输完成
            public event Action<string> FileTransCompleted;
            //////传输中断
            ////public event Action<string, FileTransDisrupttedType> FileTransDisruptted;
                     /// <summary>
            /// The name of the file
            /// 文件名  (没有带路径)
            /// </summary>
            public string Filename { get; private set; }
            /// <summary>
            /// The connectionInfo corresponding with the source
            /// 连接信息
            /// </summary>
            public ConnectionInfo SourceInfo { get; private set; }        //文件ID  用于管理文件 和文件的发送 取消发送相关        private string fileID;        public string FileID
            {
                get { return fileID; }
                set { fileID = value; }
            }
            /// <summary>
            /// The total size in bytes of the file
            /// 文件的字节大小
            /// </summary>
            public long SizeBytes { get; private set; }        /// <summary>
            /// The total number of bytes received so far
            /// 目前收到的文件的带下
            /// </summary>
            public long ReceivedBytes { get; private set; }        /// <summary>
            /// Getter which returns the completion of this file, between 0 and 1
            ///已经完成的百分比
            /// </summary>
            public double CompletedPercent
            {
                get { return (double)ReceivedBytes / SizeBytes; }            //This set is required for the application to work
                set { throw new Exception("An attempt to modify read-only value."); }
            }        /// <summary>
            /// A formatted string of the SourceInfo
            /// 源信息
            /// </summary>
            public string SourceInfoStr
            {
                get { return "[" + SourceInfo.RemoteEndPoint.ToString() + "]"; }
            }        /// <summary>
            /// Returns true if the completed percent equals 1
            /// 是否完成
            /// </summary>
            public bool IsCompleted
            {
                get { return ReceivedBytes == SizeBytes; }
            }        /// <summary>
            /// Private object used to ensure thread safety
            /// </summary>
            object SyncRoot = new object();        /// <summary>
            /// A memory stream used to build the file
            /// 用来创建文件的数据流
            /// </summary>
            Stream data;        /// <summary>
            ///Event subscribed to by GUI for updates
            /// </summary>
        
            //临时文件流存储的位置
            public string TempFilePath = "";
            //文件最后的保存路径
            public string SaveFilePath = "";        /// <summary>
            /// Create a new ReceivedFile
            /// </summary>
            /// <param name="filename">Filename associated with this file</param>
            /// <param name="sourceInfo">ConnectionInfo corresponding with the file source</param>
            /// <param name="sizeBytes">The total size in bytes of this file</param>
            public ReceivedFile(string fileID, string filename, string filePath, ConnectionInfo sourceInfo, long sizeBytes)
            {
                string tempSizeBytes = sizeBytes.ToString();            this.fileID = fileID;
                this.Filename = filename;
                this.SourceInfo = sourceInfo;
                this.SizeBytes = sizeBytes;            //如果临时文件已经存在,则添加.data后缀            this.TempFilePath = filePath + filename + ".data";
                while (File.Exists(this.TempFilePath))
                {                this.TempFilePath = this.TempFilePath + ".data";
                }
                this.SaveFilePath = filePath + filename;            //We create a file on disk so that we can receive large files
                //我们在硬盘上创建一个文件,使得我们可以接收大的文件
                data = new FileStream(TempFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read, 8 * 1024, FileOptions.DeleteOnClose);                     }        /// <summary>
            /// Add data to file
            /// 添加数据到文件中
            /// </summary>
            /// <param name="dataStart">Where to start writing this data to the internal memoryStream</param>
            /// <param name="bufferStart">Where to start copying data from buffer</param>
            /// <param name="bufferLength">The number of bytes to copy from buffer</param>
            /// <param name="buffer">Buffer containing data to add</param>
            public void AddData(long dataStart, int bufferStart, int bufferLength, byte[] buffer)
            {
                lock (SyncRoot)
                {
                    if (!this.canceled && (this.data != null))
                    {
                        try
                        {
                            data.Seek(dataStart, SeekOrigin.Begin);                        data.Write(buffer, (int)bufferStart, (int)bufferLength);                        ReceivedBytes += (int)(bufferLength - bufferStart);                        ////EventsHelper.Fire<string, long, long>(this.FileTransProgress, FileID, SizeBytes, ReceivedBytes);                        if (ReceivedBytes == SizeBytes)
                            {
                                data.Flush();
                                SaveFileToDisk(SaveFilePath);
                                data.Close();
                                EventsHelper.Fire<string>(this.FileTransCompleted, FileID);
                            }
                        }
                        catch (Exception exception)
                        {
                            //触发文件传输中断事件
                            //this.FileTransDisruptted(Filename, FileTransDisrupttedType.InnerError);                        ////EventsHelper.Fire<string, FileTransDisrupttedType>(this.FileTransDisruptted, FileID, FileTransDisrupttedType.InnerError);                    }
                    }
                }          
            }        private volatile bool canceled;        public void Cancel(FileTransFailReason disrupttedType, bool deleteTempFile)
            {
                try
                {
                    this.canceled = true;
                    this.data.Flush();
                    this.data.Close();
                    this.data = null;
                    if (deleteTempFile)
                    {
                        File.Delete(this.TempFilePath);
                    }
                }
                catch (Exception)
                {
                }
                //通知 Receiver取消,并且触发文件传输中断事件
                ////EventsHelper.Fire<string, FileTransDisrupttedType>(this.FileTransDisruptted, FileID, FileTransDisrupttedType.InnerError);
            }        /// <summary>
            /// Saves the completed file to the provided saveLocation
            /// 保存文件到指定位置
            /// </summary>
            /// <param name="saveLocation">Location to save file</param>
            public void SaveFileToDisk(string saveLocation)
            {
                if (ReceivedBytes != SizeBytes)
                    throw new Exception("Attempted to save out file before data is complete.");            if (!File.Exists(TempFilePath))
                    throw new Exception("The transferred file should have been created within the local application directory. Where has it gone?");            //File.Delete(saveLocation);            //覆盖文件
                File.Copy(TempFilePath, saveLocation, true);
            }        /// <summary>
            /// Closes and releases any resources maintained by this file
            /// </summary>
            public void Close()
            {
                try
                {
                    data.Dispose();
                }
                catch (Exception) { }            try
                {
                    data.Close();
                }
                catch (Exception) { }
            }       
        }
    }ReceivedFile