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

歡迎訪問 生活随笔!

生活随笔

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

C#

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

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

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

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

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

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

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

首先我們先需要把我們要發(fā)送的文件信息拋給服務器,這里主要需要文件的文件名和文件大小,這里我們只要在用文件流讀取文件的時候?qū)⑦@些數(shù)據(jù)提取出來即可:

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

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

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

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

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

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

if (buffer[0] == 1)//1對應文件信息 {SaveFileDialog sfDialog = new SaveFileDialog();//創(chuàng)建SaveFileDialog實例string spath = @"C:\Users\admin\Desktop";//制定存儲路徑string savePath = Path.Combine(spath, recStr);//獲取存儲路徑及文件名int rec = 0;//定義獲取接受數(shù)據(jù)的長度初始值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);//截取字節(jié)數(shù)據(jù)寫入文件中fs.Flush();//清空緩存信息recFileLength += firstRcv - 1;//記錄已獲取的數(shù)據(jù)大小firstWrite = false;//切換狀態(tài)}else{rec = socketServer.Receive(buffer);//繼續(xù)接收文件并存入緩存fs.Write(buffer, 0, rec);//將緩存中的數(shù)據(jù)寫入文件中fs.Flush();//清空緩存信息recFileLength += rec;//繼續(xù)記錄已獲取的數(shù)據(jù)大小}Console.WriteLine("{0}: 已接收數(shù)據(jù):{1}/{2}", socketServer.RemoteEndPoint, recFileLength, fileLength);//查看已接受數(shù)據(jù)進度}fs.Close();}Console.WriteLine("保存成功!!!!"); }

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

首發(fā)百度經(jīng)驗 :? ?C#實戰(zhàn)027:socket實現(xiàn)大文件傳輸?

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

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。