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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

关于CS架构文件传输流的问题,文中代码都是转自网上,但可保证代码无无误...

發布時間:2025/1/21 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 关于CS架构文件传输流的问题,文中代码都是转自网上,但可保证代码无无误... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

今天看論壇看到一個人問了這一個問題:

———————————————————————————————————————————

c#socket編程中,
客戶端通過socket.Send()傳送完文件后,
服務端,接收后,如何將那些byte的內容還原為原來的文件啊。。。
求大俠指點,謝謝

———————————————————————————————————————————————————

?

其實這個問題出現得讓人無語,卻又顯得很正常。

讓人無語是因為文件存儲的方式本就是二進制,而我們在網絡中傳輸的卻又是字節流,也就是二進制流,那么這個傳輸本就是一個復制粘貼的的問題,服務器端的文件作為做基本的二進制流傳送到客戶端,而客戶端按照接受的順序將二進制流重新寫入本地文件,則客戶端生成的本地文件與服務器端本就是一個復本。故而很南門為什么會問出還原為原來文件的問題。

但是顯得正常是因為我們面對的都是文本流,我們很多時候不需要關注二進制流,更不需要關注扇區等硬件細節性問題了。這個使得我們很多人已經忘記文件是以二進制存儲的,尤其很多從事純軟工作的,對于搗鼓過模擬電路數字電路搗鼓過bios等微機接口的人來說,很明顯的二進制存儲方式,對于純軟的人來說,可能不是那么天經地義了。這個也可以說成是軟件進步的一個體現吧,分層、模塊化、面向對象化的思想已經使我們真的從底層細節中脫離出來了。我們只需要關注我們的解決方案,卻不再需要糾纏于實現細節問題。就像我們用一個statck的時候,我們很少去問底層的棧是怎么實現的,內存分配是怎么弄的。

這也是我在上次的stringstringbuilder比較中提到的那個小白的觀點一樣,我們說string是不可變的,是常量,string s="aa"; s +="bb";內存中將存在三個字符串復本,但是那個小白卻說string s="1"; s="0"來證明string是變量,不是不可變的。這個是同樣的道理,我們從事軟件編程,卻很多人套多局限于我們自己的視野,從來沒有去問過操作系統是怎么實現的,內存是怎么分配的,進程是誰管理的,怎么管理的等等。

我們解決問題的時候需要不斷抽象不斷屏蔽,但是我們自己的知識框架可不能不斷抽象屏蔽,否則最后我們會發現一切都不再理所當然,我們會到處失措的。

下面就說一下這位同學問的問題的解決方案吧,當然這些都是大家一看就覺得很白癡的解決方案了,基礎問題的解決方案很多時候就是白癡的,但是我們卻不一定都能想起來。

/// <summary>

/// 把對象序列化并返回相應的字節

/// </summary>

/// <param name="objectToSerialize">參數:OBJECT 待序列化對象</param>

/// <returns>返回:BYTE[] 序列化后的字節流</returns>

public static byte[] SerializeObject(object objectToSerialize){

if (objectToSerialize == null) return null;

MemoryStream memoryStream = new MemoryStream();

BinaryFormatter binaryFormatter = new BinaryFormatter();

binaryFormatter.Serialize(memoryStream, objectToSerialize);

memoryStream.Position = 0;

byte[] read = new byte[memoryStream.Length];

memoryStream.Read(read, 0, read.Length);

memoryStream.Close();

return read;

}

?

/// <summary>

/// 把字節反序列化成相應的對象

/// </summary>

/// <param name="byteToDeserialize">參數:BYTE[] 待還原的字節流</param>

/// <returns>返回:OBJECT 還原后的對象</returns>

public static object DeserializeObject(byte[] byteToDeserialize)

{

object originalObject = null;

if (byteToDeserialize == null)

return originalObject;

MemoryStream memoryStream = new MemoryStream(byteToDeserialize);

memoryStream.Position = 0;

BinaryFormatter formatter = new BinaryFormatter();

originalObject = formatter.Deserialize(memoryStream);

memoryStream.Close();

return originalObject;

}

?

這個是本地進程中實現的,通過MemoryStreamBinaryFormatter來實現的。

?

當然網絡傳輸,我們更多的是通過FileStream來實現的。完整示例如下:

客戶端Client:

public partial class ClientFrm : Form

{

private int size =66530000;

public ClientFrm()

{

InitializeComponent();

}

//發送文件

private void btnSendFile_Click(object sender, EventArgs e)

{FileSend();}

/// <summary>

/// 負責向服務器發送文件

/// </summary>

private void FileSend()

{

try

{

DialogResult result;

//當點擊取消或文件名為空時終止程序

result = openFileDig.ShowDialog();

if (result == DialogResult.Cancel || openFileDig.FileName == "" || txtHostName.Text == "" || txtPort.Text == "")

{

MessageBox.Show("條件不全!");

return;

}

//tctClient對象可指定主機名和端口

TcpClient tc = new TcpClient(txtHostName.Text.Trim(), int.Parse(txtPort.Text.Trim()));

//創建網絡流

NetworkStream ns = tc.GetStream();

//創建一個文件流,并將打開的文件以字節流形式讀入內存

FileStream fsByte = new FileStream(@openFileDig.FileName, FileMode.Open, FileAccess.Read);

byte[] a = InsertFileSign(ns, fsByte);

int sCount = 0,curLen=0;

double c = 0.0, f = (double)fsByte.Length;

while (sCount < ((int)fsByte.Length) && ns.CanWrite)

{

byte[] byts = new Byte[size];

curLen =fsByte.Read(byts, 0, byts.Length);

ns.Write(byts, 0, curLen);

sCount = sCount + curLen;

c = sCount;

progressBar1.Value =Convert.ToInt32((c / f) * 100);

this.Refresh();

}

progressBar1.Value = 100;

//關閉打開的流

fsByte.Flush();

fsByte.Close();

ns.Flush();

ns.Close();

tc.Close();

this.Refresh();

MessageBox.Show("文件發送成功!");

progressBar1.Value = 0;

}

catch (Exception ex)

{

MessageBox.Show(ex.Message);

}

finally { }

}

/// <summary>

/// 向傳輸的文件寫入文件結構信息標記

/// </summary>

/// <param name="ns"></param>

/// <param name="fsByte"></param>

/// <returns></returns>

private byte[] InsertFileSign(NetworkStream ns, FileStream fsByte)

{

string[] name = new string[openFileDig.FileName.Length];

name = openFileDig.FileName.Split(new char[] { '\\' });

//自定義編碼方式#MName#文件名.擴展名#MLen#文件長度#End#"

string sign1 = "#MName#" + name[name.Length - 1] + "#MLen#" + fsByte.Length.ToString() + "#End#";

byte[] a = StringTOByts(sign1);

ns.Write(a,0,a.Length);

return a;

}

//將字符串轉換為字節數組

public byte[] StringTOByts(string str)

{ //當字符向字節轉換是2個字節表示一個字符

byte[] byts = new Byte[1000];

char[] chs = str.ToCharArray();

for (int index = 0; index < chs.Length; index++)

{ //取出字符的低8位并將二進制轉換位十進制存入字節數組

byts[index * 2] = (byte)(chs[index] & 0xFF);

//用右移8位取出高8位并將二進制轉換位十進制存入字節數組

byts[index * 2 + 1] = (byte)((chs[index] >> 8) & 0xFF);

}

//剩余空間用0填充

for (int i = (str.Length * 2); i < 1000; i++)

{

byts[i] = 0;

}

return byts;

}

?

private void btnCance_Click(object sender, EventArgs e)

{

this.Close();

}

}

服務器端:

public partial class ServerFrm : Form

{

private string paths=@"D:\";

private int size =66530000;

public ServerFrm()

{

InitializeComponent();

}

?

private void button1_Click(object sender, EventArgs e)

{

DialogResult result;

//當點擊取消或文件名為空時終止程序

result = openPath.ShowDialog();

if (result == DialogResult.Cancel || txtHostName.Text == "" || txtPort.Text == "")

{

MessageBox.Show("條件不全或保存路徑為空!");

return;

}

else

paths = openPath.FileName;

ReceivedFile();

}

/// <summary>

/// 接收文件

/// </summary>

private TcpListener tpclis=null;

private FileStream fsWriteFile = null;

private void ReceivedFile()

{

try

{

//IPHostEntry hostInfo = Dns.GetHostByAddress("127.0.0.1");

//IPAddress[] ipAddree =hostInfo.AddressList;

//IPAddress ip = ipAddree[0];

獲得本地Ip

IPAddress ip = IPAddress.Parse(txtHostName.Text.Trim());

//監聽本地端口

tpclis = new TcpListener(ip, int.Parse(txtPort.Text.Trim()));

tpclis.Start();

//創建接收文件線程

Thread thread = new Thread(new ThreadStart(GetFileData));

Control.CheckForIllegalCrossThreadCalls = false;

thread.IsBackground = true;

thread.Start();

//GetFileData();

}

catch (Exception ex)

{

MessageBox.Show(ex.Message);

}

finally { }

}

//獲得文件數據

private void GetFileData()

{

while (true)

{

TcpClient tc=tpclis.AcceptTcpClient();

//獲得網絡流

NetworkStream ns = tc.GetStream();

int MLen;

string Mname;

?

GetFileSignInfo(ns, out MLen, out Mname);

//檢查路徑如果不存在就創建它

bool fag=Directory.Exists(paths);

if (!fag)

Directory.CreateDirectory(paths);

?

//創建文件

fsWriteFile = new FileStream(paths +@"\"+ Mname, FileMode.OpenOrCreate);

int sCount = 0, curLen = 0;

double c = 0.0,f=MLen;

while (sCount < MLen && ns.CanRead)

{

byte[] file = new Byte[size];

curLen = ns.Read(file, 0, file.Length);

fsWriteFile.Write(file, 0, curLen);

sCount = sCount + curLen;

c = sCount;

progressBar1.Value =Convert.ToInt32((c / f) * 100);

}

progressBar1.Value = 100;

fsWriteFile.Flush();

fsWriteFile.Close();

ns.Flush();

ns.Close();

MessageBox.Show("文件已收到!");

progressBar1.Value = 0;

}

}

/// <summary>

/// 獲得文件標記信息

/// </summary>

/// <param name="ns"></param>

/// <param name="bytes"></param>

/// <param name="MLen"></param>

/// <param name="Mname"></param>

private void GetFileSignInfo(NetworkStream ns, out int MLen, out string Mname)

{

byte[] a = new Byte[1000];

ns.Read(a, 0, 1000);

string str = BytsTOString(a, 1000);

//解析規則"#98#MName#光良 - 童話.mp3#MLen#244582#End#";

int ln1 = str.IndexOf("#MName#", 0);

int ln2 = str.IndexOf("#MLen#", ln1 + 6);

int ln3 = str.IndexOf("#End#", ln2 + 5);

//獲得文件參數

MLen = int.Parse(str.Substring(ln2 + 6, ln3 - ln2 - 6));//獲得歌曲長度

Mname = str.Substring(ln1 + 7, ln2 - ln1 - 7);//獲得歌曲名及擴展名

}

?

private void button2_Click(object sender, EventArgs e)

{

this.Close();

}

//將字節型數據轉換成字符串

public string BytsTOString(byte[] byts, int len)

{

string str = ""; char ch;

for (int index = 0; index < len / 2; index++)

{

ch = (char)(byts[index * 2] + (byts[index * 2 + 1] << 8));

str += ch;

}

?

return str;

}

?

/// <summary>

/// 把對象序列化并返回相應的字節

/// </summary>

/// <param name="objectToSerialize">參數:OBJECT 待序列化對象</param>

/// <returns>返回:BYTE[] 序列化后的字節流</returns>

public static byte[] SerializeObject(object objectToSerialize)

{

if (objectToSerialize == null)

return null;

MemoryStream memoryStream = new MemoryStream();

BinaryFormatter binaryFormatter = new BinaryFormatter();

binaryFormatter.Serialize(memoryStream, objectToSerialize);

memoryStream.Position = 0;

byte[] read = new byte[memoryStream.Length];

memoryStream.Read(read, 0, read.Length);

memoryStream.Close();

return read;

}

?

/// <summary>

/// 把字節反序列化成相應的對象

/// </summary>

/// <param name="byteToDeserialize">參數:BYTE[] 待還原的字節流</param>

/// <returns>返回:OBJECT 還原后的對象</returns>

public static object DeserializeObject(byte[] byteToDeserialize)

{

object originalObject = null;

if (byteToDeserialize == null)

return originalObject;

MemoryStream memoryStream = new MemoryStream(byteToDeserialize);

memoryStream.Position = 0;

BinaryFormatter formatter = new BinaryFormatter();

originalObject = formatter.Deserialize(memoryStream);

memoryStream.Close();

return originalObject;

}

?

?

}

?

上面這個例子也順并解決了另一個同學的問題,他問的是如何解析出文件的名稱作者等信息。最原始的方法就是通過協議來解決。自己定義傳輸的二進制流的協議。這樣服務器端對著接受的到的字節流,按照協議來解析既可。

轉載于:https://www.cnblogs.com/BLoodMaster/archive/2010/07/02/1769924.html

總結

以上是生活随笔為你收集整理的关于CS架构文件传输流的问题,文中代码都是转自网上,但可保证代码无无误...的全部內容,希望文章能夠幫你解決所遇到的問題。

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