C# 通过TCP发送/接收文件

C# 通过TCP发送/接收文件,c#,file,tcp,send,C#,File,Tcp,Send,可能重复: 我正在尝试通过TCP将文件从服务器发送到客户端 服务器端代码,发送文件: NetworkStream netStream = client.GetStream(); FileStream fs = new FileStream("usb.exe",FileMode.Open, FileAccess.Read); byte[] data = new byte[fs.Length]; fs.Read(data,0, data.Length); fs.Flush(); fs.Close

可能重复:

我正在尝试通过TCP将文件从服务器发送到客户端

服务器端代码,发送文件:

NetworkStream netStream = client.GetStream();
FileStream fs = new FileStream("usb.exe",FileMode.Open, FileAccess.Read);
byte[] data = new byte[fs.Length];
fs.Read(data,0, data.Length);
fs.Flush();
fs.Close();

netStream.Write(data, 0, data.Length);
netStream.Flush();
客户端代码,接收文件:

FileStream str = new FileStream("usb.exe", FileMode.Create, FileAccess.Write);
byte[] data = new byte[1024];

while ((dataCitit = netStream.Read(data,0, data.Length)) > 0)
    {
         Thread.Sleep(25);
         Application.DoEvents();

         str.Write(data, 0, dataCitit);
         totalbytes += dataCitit;                      
    }
str.Close();
有人能指出我哪里弄错了吗

该文件有1036KB,它只发送1032KB,然后被卡住,无法在客户端退出while循环

另外,如果我关闭服务器并快速打开它,它会发送最后的字节,而文件会完全发送。(此文件完全打开)


我认为服务器端不发送所有字节是个问题,但为什么和在哪里…

首先,这是服务器端代码中的一个问题:

fs.Read(data,0, data.Length);
您忽略了
Read
返回的值。永远不要那样做。使用
FileStream
您可能还可以,但我个人不会相信它。如果您使用的是.NET4,那么无论如何都不需要这样做-只需使用
Stream.CopyTo

在客户端代码中,最大的初始问题是在UI线程上执行所有这些操作。这是一个糟糕的想法-如果出现网络故障,用户界面将冻结,因为
Read
调用被阻塞

同样,只需使用
Stream.CopyTo
,但要在后台线程中执行

此外,在所有这些情况下,对流使用
using
语句,这样无论发生什么情况,都可以干净地关闭它们

这只是一般的卫生问题。现在,至于你为什么被绞死

。。。您没有关闭服务器端的网络流。因此,您永远不会在客户端到达流的末尾。如果您只需要为单个文件使用连接,那么答案很简单:只需关闭服务器端的连接

但是,如果您需要对多个文件使用相同的连接,那么您需要更多的协议—您需要以某种方式指示数据的结束。有三种常见的方法:

  • 在数据本身之前写入数据的长度,然后在读取端,首先读取长度,然后读取那么多字节,如果流在您完成之前就完成,则会失败。这要求您在开始编写之前知道要编写多少数据
  • 使用“数据结束”标记,您可以在读取端检测到该标记;一般来说,这是一种痛苦,因为如果标记出现在文本本身中,则需要将其转义
  • 第一种方法的一种变体,每次写入一个长度前缀块,然后写入一个零长度块以指示“数据结束”。这是非常灵活的,但是如果第一种方法确实适合您,那么显然比第一种方法要多做一些工作

首先,这是服务器端代码中的一个问题:

fs.Read(data,0, data.Length);
您忽略了
Read
返回的值。永远不要那样做。使用
FileStream
您可能还可以,但我个人不会相信它。如果您使用的是.NET4,那么无论如何都不需要这样做-只需使用
Stream.CopyTo

在客户端代码中,最大的初始问题是在UI线程上执行所有这些操作。这是一个糟糕的想法-如果出现网络故障,用户界面将冻结,因为
Read
调用被阻塞

同样,只需使用
Stream.CopyTo
,但要在后台线程中执行

此外,在所有这些情况下,对流使用
using
语句,这样无论发生什么情况,都可以干净地关闭它们

这只是一般的卫生问题。现在,至于你为什么被绞死

。。。您没有关闭服务器端的网络流。因此,您永远不会在客户端到达流的末尾。如果您只需要为单个文件使用连接,那么答案很简单:只需关闭服务器端的连接

但是,如果您需要对多个文件使用相同的连接,那么您需要更多的协议—您需要以某种方式指示数据的结束。有三种常见的方法:

  • 在数据本身之前写入数据的长度,然后在读取端,首先读取长度,然后读取那么多字节,如果流在您完成之前就完成,则会失败。这要求您在开始编写之前知道要编写多少数据
  • 使用“数据结束”标记,您可以在读取端检测到该标记;一般来说,这是一种痛苦,因为如果标记出现在文本本身中,则需要将其转义
  • 第一种方法的一种变体,每次写入一个长度前缀块,然后写入一个零长度块以指示“数据结束”。这是非常灵活的,但是如果第一种方法确实适合您,那么显然比第一种方法要多做一些工作

这个答案似乎对你有帮助:这个答案似乎对你有帮助:谢谢你的回答,我只是来编辑我的问题。就像你说的,这是因为我没有关闭服务器端的网络流。我将搁置您的建议,并使用上述方法之一,因为我不想关闭流。再次感谢。另外,如果你能给我举一个第一种方法的例子,写下数据的长度,if将非常有用。@Spreadzz:不,你应该自己试试,如果你有问题,可以问一个具体的问题。你可能想考虑使用<代码> BinaryWriter < /代码>和<代码> BinaryReader < /代码>,这使事情变得更简单。如果我错了,请纠正我,BinaryReader和BinaryWriter是用来写和读和结束数据标记的。还有一个问题,在客户端,我的int DATAcItTe= NETStask.Read(数据,0,数据,长度)如果我不关闭服务器端的流,会有0吗?谢谢你的回答,我只是来编辑我的问题。就像你说的,这是因为我没有关闭服务器端的网络流。我将搁置您的建议,并使用上述方法b