日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C#实战027:socket实现大文件传输

發布時間:2024/3/26 C# 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C#实战027:socket实现大文件传输 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前面寫了一個單文件傳輸的,后來發現當傳送的文件大于設置的緩存空間時,文件就會出現丟包的現象,導致文件無法使用,所以為了適應大文件的傳輸,這里我將代碼進行了下修改,實現大文件傳輸。

不過socket實現大文件傳輸有個缺點,由于傳輸過程是通過字節緩存發送,接受也是讀寫字節,導致整個傳輸過程效率不高,我嘗試了一個169MB的視頻文件傳輸,雖然傳完了,但是耗時將近1小時。

因為計算機緩存有限,所以不可能開啟太大的緩存來緩存數據的,所以當我們要發送文件較大的文件時我們就要進行分段處理,分段讀取,分段發送保存。大家可以看到我們的兩個窗口都是同步的,一遍在讀取中,一遍就在寫入中。如此反復的使用同一塊緩存進行數據傳遞。

首先我們先進行循環讀取文件信息,這里有個重要的就是做好標記,之前寫?C#實戰026:socket實現單文件傳輸時就有提到,通過在第一個字節做標記來區分我們傳送的信息是什么信息,這個規則自己定義,只要客戶端和服務端同步即可

這里我們把0定義成信息發送,1定義成文件發送,2定義成文件頭信息發送

首先我們先需要把我們要發送的文件信息拋給服務器,這里主要需要文件的文件名和文件大小,這里我們只要在用文件流讀取文件的時候將這些數據提取出來即可:

//1. 第一步:發送一個文件,表示文件名和長度,讓客戶端知道文件大小 string fileName = Path.GetFileName(filePath);//提取文件名 Console.WriteLine("發送的文件名是:" + fileName);//查看獲取文件名是否正確 long fileLength = fsRead.Length;//獲取文件長度 Console.WriteLine("發送的文件長度為:"+fileLength);//查看文件長度是否正確 string totalMsg = string.Format("{0}-{1}", fileName, fileLength);//將文件名和文件長度存入一條數據中 byte[] buffer = Encoding.UTF8.GetBytes(totalMsg); //將字符串轉換成字節數組 byte[] newBuffer = new byte[buffer.Length + 1];//新建字節數組,增加一個字節空間 newBuffer[0] = 2;//將第一個字節標記成2,代表為文件頭信息 Buffer.BlockCopy(buffer, 0, newBuffer, 1, buffer.Length);//偏移復制字節數組 socketClient.Send(newBuffer);//發送文件文件名和長度發過去

既然是循環寫入,我們就要記錄當前文件的數據大小和已讀取的數據信息,這樣循環才有終點,定義一個5M緩存區。

byte[] Filebuffer = new byte[1024 * 1024 * 5];//定義5MB的緩存空間(1024字節(b)=1千字節(kb)) int readLength = 0; //定義讀取的長度 bool firstRead = true;//定義首次讀取的狀態 long sentFileLength = 0;//定義發送的長度

接下里解釋對文件進行分包發送了,這里唯一要注意的就是第一次發送的時候要為文件價格標記,也就是第一個數據包前加標記,這樣服務端才好去識別該數據是什么數據,然后做對應的處理。

while (readLength> 0 && sentFileLength < fileLength) {sentFileLength += readLength;//計算已讀取文件大小//第一次發送的字節流上加個前綴1if (firstRead){byte[] firstBuffer = new byte[readLength + 1];//這個操作同樣也是用來標記文件的firstBuffer[0] = 1;//將第一個字節標記成1,代表為文件Buffer.BlockCopy(buffer, 0, firstBuffer, 1, readLength);//偏移復制字節數組socketClient.Send(firstBuffer, 0, readLength + 1, SocketFlags.None);Console.WriteLine("第一次讀取數據成功,在前面添加一個標記");//發送文件數據包firstRead = false;//切換狀態,避免再次進入continue;}socketClient.Send(buffer, 0, readLength, SocketFlags.None);//繼續發送剩下的數據包Console.WriteLine("{0}: 已發送數據:{1}/{2}", socketClient.RemoteEndPoint, sentFileLength, fileLength);//查看發送進度 } fsRead.Close();//關閉文件流 Console.WriteLine("發送完成");//提示發送完畢

接下來在可以在服務端來接受數據了,同樣在處理數據的時候要把第一次數據分開,因為第一組數據中添加一個標記符,所以我們在寫數據的時候要截取標記后面的數據。

if (buffer[0] == 1)//1對應文件信息 {SaveFileDialog sfDialog = new SaveFileDialog();//創建SaveFileDialog實例string spath = @"C:\Users\admin\Desktop";//制定存儲路徑string savePath = Path.Combine(spath, recStr);//獲取存儲路徑及文件名int rec = 0;//定義獲取接受數據的長度初始值long recFileLength = 0;bool firstWrite = true;using (FileStream fs = new FileStream(savePath, FileMode.Create, FileAccess.Write)){while (recFileLength < fileLength)//判斷讀取文件長度是否小于總文件長度{if (firstWrite)//第一次寫入時{fs.Write(buffer, 1, firstRcv - 1);//截取字節數據寫入文件中fs.Flush();//清空緩存信息recFileLength += firstRcv - 1;//記錄已獲取的數據大小firstWrite = false;//切換狀態}else{rec = socketServer.Receive(buffer);//繼續接收文件并存入緩存fs.Write(buffer, 0, rec);//將緩存中的數據寫入文件中fs.Flush();//清空緩存信息recFileLength += rec;//繼續記錄已獲取的數據大小}Console.WriteLine("{0}: 已接收數據:{1}/{2}", socketServer.RemoteEndPoint, recFileLength, fileLength);//查看已接受數據進度}fs.Close();}Console.WriteLine("保存成功!!!!"); }

我把源碼傳在CSDN了,有興趣的可以下載:??Socket傳輸大文件(發送與接收源碼)

首發百度經驗 :? ?C#實戰027:socket實現大文件傳輸?

歡迎關注本人的公眾號:編程手札,文章也會在公眾號更新

總結

以上是生活随笔為你收集整理的C#实战027:socket实现大文件传输的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。