在C#中通过网络发送大文件的好方法?

我正在尝试构建一个可以从网络中另一台机器上运行的服务请求文件的应用程序。 这些文件可能相当大(有时500mb +)。 我正在考虑通过TCP发送它,但我担心它可能需要将整个文件存储在内存中。

可能只有一个客户。 也不接受复制到共享目录。 唯一需要的通信是客户端说“gimme xyz”和发送它的服务器(以及确保正确发生这种情况所需的一切)。

有什么建议?

这是一种更简单的方法。 使用BITS(后台智能传输服务)。 它已经内置到WinXP和Vista中。 它基本上是驱动Windows更新的原因。

http://blogs.msdn.com/powershell/archive/2009/01/11/transferring-large-files-using-bits.aspx

http://blogs.msdn.com/jamesfi/archive/2006/12/23/how-to-use-bits-to-transfer-files.aspx

这是一个很好的托管BITS包装,有人写,以及如何使用它。

http://www.codeproject.com/KB/cs/Managed_BITS.aspx

您可以使用.NET中的套接字来传输文件和数据。

您可能想要考虑WCF流 。

本文可能对您有所帮助。 它是关于在.NET中发送大文件。 检查链接:

http://codetechnic.blogspot.com/2009/02/sending-large-files-over-tcpip.html

小心BITS。 这是一个非常好的协议,但不是Windows更新程序的关键部分。 我们发现几乎没有任何公司客户允许BITS更新到他们的机器上; 因此我们无法构建依赖它的应用程序。

通过开源edtFTPnet库使用FTP。 快速而简单。

使用TransmitFile (这是一个Win32函数;也许它也是.NET库的一种方法)。

如果FTP是一个选项,那么为了简单起见,我会选择它。 否则,您将进入TCP / IP套接字编程的世界。

如果文件在物理上存在于机器上,为什么不将它们放在文件夹中,使该文件夹成为IIS中的虚拟目录,并使用基于内容的路由和/或URL重写将请求路由到它们。

就个人而言,我会寻求平衡速度,可靠性和经济代码的东西,所以我将它建立在TCP网络流上。 代码的客户端看起来像这样:

 internal class Client { private FileStream _fs; private long _expectedLength; public void GetFileFromServer(string localFilename) { if (File.Exists(localFilename)) File.Delete(localFilename); _fs = new FileStream(localFilename, FileMode.Append); var ipEndpointServer = new IPEndPoint(IPAddress.Parse({serverIp}), {serverPort}); // an object that wraps tcp client var client = new TcpClientWrapper(ipEndpointServer, ""); client.DataReceived += DataReceived; } private void DataReceived(object sender, DataReceivedEventArgs e) { var data = e.Data; // first packet starts with 4 bytes dedicated to the length of the file if (_expectedLength == 0) { var headerBytes = new byte[4]; Array.Copy(e.Data, 0, headerBytes, 0, 4); _expectedLength = BitConverter.ToInt32(headerBytes, 0); data = new byte[e.Data.Length - 4]; Array.Copy(e.Data, 4, data, 0, data.Length); } _fs.WriteAsync(e.Data, 0, e.Data.Length); if (_fs.Length >= _expectedLength) { // transfer has finished } } } 

然后有一个服务器类来提供文件。 注意整个文件是如何加载到内存中的,而不是从FileStream读取的。

 internal class Server { private TcpServer _tcpServer; private NetworkStream _stream; public void StartServer() { // fire up a simple Tcp server _tcpServer = new TcpServer({serverPort}, "test"); _tcpServer.ClientConnected += ClientConnected; } private void ClientConnected(object sender, TcpClientConnectedEventArgs e) { // an incoming client has been detected ... send the file to that client! _stream = e.Client.GetStream(); SendFileToClient({pathToFile}); } private void SendFileToClient(string pathToFile) { // open the file as a stream and send in chunks using (var fs = new FileStream(pathToFile, FileMode.Open)) { // send header which is file length var headerBytes = new byte[4]; Buffer.BlockCopy(BitConverter.GetBytes(fs.Length + 4), 0, headerBytes, 0, 4); _stream.Write(headerBytes, 0, 4); // send file in block sizes of your choosing var buffer = new byte[100000]; int bytesRead = 0; while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0) { _stream.Write(buffer, 0, bytesRead); } _stream.Flush(); } } } 

TcpClientWrapper几乎是带有System.Net.Sockets.TcpClient对象和底层NetworkStream对象的样板代码。 我也不需要发布这个,但只是给出一些建议,其中包含这样的内容:

 _tcp = new Net.TcpClient(); _tcp.Connect(remoteEp); _stream = _tcp.GetStream(); _stream.BeginRead(_receivedData, 0, _receivedData.Length, DataReceivedAsync, null); 

并且DataReceivedAsync方法是样板插槽数据处理,并且会引发一个事件o将收到的数据共享回消费者(在这种情况下是客户端):

 private void DataReceivedAsync(IAsyncResult ar) { var receivedBytes = _stream.EndRead(ar); if (receivedBytes > 0) { var data = new byte[receivedBytes]; Array.Copy(_receivedData, 0, data, 0, receivedBytes); DataReceived?.Invoke(this, new DataReceivedEventArgs(data)); _receivedData = new byte[ReceiveBufferSize]; _stream.BeginRead(_receivedData, 0, _receivedData.Length, DataReceivedAsync, null); } } 

将数据从包装器发送回客户端的事件:

 public EventHandler DataReceived; public class DataReceivedEventArgs : EventArgs { public DataReceivedEventArgs(byte[] data) { Data = data; } public byte[] Data { get; } }