国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

分析下Neworkcomms中的文件傳輸

2019-11-17 02:35:11
字體:
來源:轉載
供稿:網友

分析下Neworkcomms中的文件傳輸

NetworkComms網絡通信框架序言

文件傳輸在客戶端,服務器端程序的應用是非常廣泛的,穩定的文件傳輸應該可以說是Tcp通訊的核心功能。下面我們來看一下如何基于networkcomms2.3.1來進行文件傳輸。最新的 v3版本做了一些加強,變化不是很大。

使用networkcomms2.3.1框架,您無需考慮粘包等問題,框架已經幫您處理好了。

我們看一下如何發送文件,相關代碼如下:

發送文件:public  void StartSendFile()        {            //聲明一個文件流            FileStream stream = null;            try            {                //FilePath是文件路徑,打開這個文件                //根據選擇的文件創建一個文件流                 stream = new FileStream(this.FilePath, FileMode.Open, Fileaccess.Read, FileShare.Read);                                                 //包裝成線程安全的數據流                 ThreadSafeStream safeStream = new ThreadSafeStream(stream);             //獲取不包含路徑信息的文件名                string shortFileName = System.IO.Path.GetFileName(FilePath);                                  //根據參數中設定的值來角色發送的數據包的大小 因為文件很大 可能1個G 2個G 不可以一次性都發送                //每次都只發送一部分 至于每次發送多少 我們創建了一個fileTransOptions類來進行設定                               long sendChunkSizeBytes = fileTransOptions.PackageSize;                //總的文件大小                this.SizeBytes = stream.Length;                long totalBytesSent = 0;                //用一個循環方法發送數據,直到發送完成                do                {                    //如果剩下的字節小于上面指定的每次發送的字節,即PackageSize的值,那么發送此次發送的字節數為 剩下的字節數  否則 發送的字節長度為 PackageSize                    long bytesToSend = (totalBytesSent + sendChunkSizeBytes < stream.Length ? sendChunkSizeBytes : stream.Length - totalBytesSent);                                      //從ThreadSafeStream線程安全流中獲取本次發送的部分           (線程安全流,totalbytesSent 是已發送的數,在此處代表從ThreadSafeStream中截取的文件的開始位置,bytesToSend 代表此次截取的文件的長度)                    StreamSendWrapper streamWrapper = new StreamSendWrapper(safeStream, totalBytesSent, bytesToSend);              //我們希望記錄包的順序號                    long packetSequenceNumber;                   //發送文件的數據部分 并返回此次發送的順序號 這個順序號在下面的發送文件信息時會用到 起到一個對應的作用。                    connection.SendObject("PartialFileData", streamWrapper, sendFileOptions, out packetSequenceNumber);                                       //發送上面的文件的數據部分向對應的信息  包括文件ID  文件名  在服務器上存儲的位置  文件的總長度  totalBytesSent是已發送數,在此處用來傳遞給服務器后,服務器用來定位此部分數據存放的位置 進一步合成文件                    connection.SendObject("PartialFileDataInfo", new SendInfo(fileID, shortFileName, destFilePath, stream.Length, totalBytesSent, packetSequenceNumber), sendFileOptions);                    totalBytesSent += bytesToSend;                    //更新已經發送的字節的屬性                    SentBytes += bytesToSend;                                      //觸發一個事件 UI可以依據此事件更新PRogressBar 動態的顯示文件更新的過程                    FileTransProgress.Raise(this, new FTProgressEventArgs(FileID, SizeBytes, totalBytesSent));                    //每發送一部分文件 都Sleep幾十毫秒,不然cpu會非常高                    if (!((this.fileTransOptions.SleepSpan <= 0) || this.canceled))                    {                        Thread.Sleep(this.fileTransOptions.SleepSpan);                    }                } while ((totalBytesSent < stream.Length) && !this.canceled);                if (!this.canceled)                {                    //觸發文件傳輸完成事件 UI可以調閱此事件 并彈出窗口報告文件傳輸完成                    FileTransCompleted.Raise(this, new FTCompleteEventArgs(fileID));                }                else                {                    //觸發文件傳輸中斷事件                    FileTransDisruptted.Raise(this, new FTDisruptEventArgs(FileID, FileTransFailReason.Error));                }             }            catch (CommunicationException ex)            {                                LogTools.LogException(ex, "SendFile.StartSendFile");                FileTransDisruptted.Raise(this, new FTDisruptEventArgs(FileID, FileTransFailReason.Error));            }            catch (Exception ex)            {                LogTools.LogException(ex, "SendFile.StartSendFile");                FileTransDisruptted.Raise(this, new FTDisruptEventArgs(FileID, FileTransFailReason.Error));            }            finally            {                if (stream != null)                {                    stream.Close();                }            }        }

接收文件 首先聲明2個字典類 用來存放接收到的文件 和接收到的文件信息

 /// <summary>        /// 文件數據緩存   索引是 ConnectionInfo對象  數據包的順序號  值是數據        /// </summary>        Dictionary<ConnectionInfo, Dictionary<long, byte[]>> incomingDataCache = new Dictionary<ConnectionInfo, Dictionary<long, byte[]>>();        /// <summary>        /// 文件信息數據緩存     索引是 ConnectionInfo對象  數據包的順序號  值是文件信息數據        /// </summary>        Dictionary<ConnectionInfo, Dictionary<long, SendInfo>> incomingDataInfoCache = new Dictionary<ConnectionInfo, Dictionary<long, SendInfo>>();

在接收端定義2個相對應的文件接收方法 一個用來接收文件字節部分 一個用來接收文件字節部分對應的信息類

一般在構造函數中聲明

            //處理文件數據              NetworkComms.AppendGlobalIncomingPacketHandler<byte[]>("PartialFileData", IncomingPartialFileData);            //處理文件信息              NetworkComms.AppendGlobalIncomingPacketHandler<SendInfo>("PartialFileDataInfo", IncomingPartialFileDataInfo);

接收文件字節

    private void IncomingPartialFileData(PacketHeader header, Connection connection, byte[] data)        {            try            {                SendInfo info = null;                ReceiveFile file = null;                //以線程安全的方式執行操作                lock (syncRoot)                {                                        //獲取數據包的順序號                    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);                                                //檢查相關連接上的文件是否存在,如果不存在,則添加相關文件{ReceiveFile}                        if (!recvManager.ContainsFileID(info.FileID))                        {                                                         recvManager.AddFile(info.FileID, info.Filename, info.FilePath, connection.ConnectionInfo, info.TotalBytes);                        }                        file = recvManager.GetFile(info.FileID);                    }                    else                    {                                              //如果不包含順序號,也不包含相關"連接信息",添加相關連接信息                        if (!incomingDataCache.ContainsKey(connection.ConnectionInfo))                            incomingDataCache.Add(connection.ConnectionInfo, new Dictionary<long, byte[]>());                        //在數據字典中添加相關"順序號"的信息                        incomingDataCache[connection.ConnectionInfo].Add(sequenceNumber, data);                    }                }                             if (info != null && file != null && !file.IsCompleted)                {                    file.AddData(info.BytesStart, 0, data.Length, data);                                        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)            {                                LogTools.LogException(ex, "IncomingPartialFileDataError");            }        }
 private void IncomingPartialFileDataInfo(PacketHeader header, Connection connection, SendInfo info)        {            try            {                byte[] data = null;                ReceiveFile file = null;                //以線程安全的方式執行操作                lock (syncRoot)                {                                    //從 SendI
上一篇:HDU 2037 (貪心)

下一篇:Aoite 系列(03)

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 公主岭市| 清镇市| 城市| 乃东县| 新昌县| 南部县| 双柏县| 荣成市| 枞阳县| 北辰区| 兴化市| 宣武区| 渝北区| 乌兰察布市| 五台县| 永丰县| 南丹县| 和林格尔县| 厦门市| 嘉禾县| 庄浪县| 如东县| 新营市| 敦煌市| 温宿县| 宁安市| 丹东市| 罗江县| 鹤庆县| 海盐县| 家居| 渝中区| 宜州市| 康乐县| 吴堡县| 乌鲁木齐县| 临武县| 左权县| 和顺县| 柳河县| 富平县|