Un bon moyen d’envoyer un fichier volumineux sur un réseau en C #?

J’essaie de créer une application capable de demander des fichiers à un service exécuté sur une autre machine du réseau. Ces fichiers peuvent être assez volumineux (500 Mo + parfois). Je cherchais à l’envoyer via TCP mais je crains que cela puisse nécessiter que tout le fichier soit stocké en mémoire.

Il n’y aura probablement qu’un seul client. Copier dans un répertoire partagé n’est pas acceptable non plus. La seule communication requirejse est que le client dise “gimme xyz” et que le serveur l’envoie (et tout ce qui est nécessaire pour que cela se produise correctement).

Aucune suggestion?

Voici un moyen plus facile. Utilisation de BITS (Background Intelligent Transfer Service). Il est déjà intégré à WinXP et à Vista. C’est essentiellement ce qui motive les mises à jour 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

Voici un bon wrapper BITS géré que quelqu’un a écrit et comment l’utiliser.

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

Vous pouvez utiliser des sockets dans .NET pour transférer des fichiers et des données.

Vous voudrez peut-être envisager le streaming WCF .

Cet article peut vous aider. Il s’agit d’envoyer des fichiers volumineux dans .NET. Vérifiez le lien:

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

Soyez prudent avec BITS. C’est un très bon protocole mais pas une partie critique du programme de mise à jour de Windows. Nous avons constaté que pratiquement aucune de nos entresockets clientes n’avait autorisé la mise à jour BITS sur leurs machines; par conséquent, nous ne pouvions pas construire une application qui en dépendait.

Utilisez FTP via la bibliothèque open source edtFTPnet . Simple et rapide

Utilisez TransmitFile (qui est une fonction Win32; c’est peut-être aussi une méthode de la bibliothèque .NET).

Si le FTP était une option, je choisirais cette solution par souci de simplicité. Sinon, vous entrez dans un monde de programmation de socket TCP / IP.

Si des fichiers existent physiquement sur la machine, pourquoi ne pas les placer simplement dans un dossier, faire de ce dossier un répertoire virtuel dans IIS et utiliser le routage basé sur le contenu et / ou la réécriture d’URL pour acheminer les demandes.

Personnellement, je choisirais un système alliant vitesse, fiabilité et code économique. Je le baserais donc sur un stream réseau TCP. Le côté client du code ressemblerait à ceci:

 internal class Client { private FileStream _fs; private long _expectedLength; public void GetFileFromServer(ssortingng 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 } } } 

Ensuite, avoir une classe de serveur pour servir le fichier. Notez que le fichier entier n’est pas chargé en mémoire mais qu’il est lu en morceaux à partir d’un 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(ssortingng 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 est à peu près le code de la plaque de chaudière avec l’object System.Net.Sockets.TcpClient et l’object NetworkStream sous-jacent. Je n’ai pas vraiment besoin de poster ça aussi, mais juste pour donner quelques indications, la construction contiendrait quelque chose comme ça:

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

et la méthode DataReceivedAsync est le traitement des données de socket DataReceivedAsync et DataReceivedAsync un événement o partager les données reçues avec le consommateur (le client dans ce cas):

 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); } } 

L’événement pour renvoyer les données du wrapper au client:

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