2017-08-16 3 views
0

J'ai écrit un programme qui génère des sommes de contrôle sur des fichiers. Tout fonctionne bien sur une machine locale, mais ralentit énormément et se tourne vers **** quand je branche sur des machines distantes en raison de la vitesse du réseau (évidemment).Comment écrire un programme homologue pouvant être appelé à distance pour effectuer des calculs sur une machine distante?

Comment écrire un programme homologue pouvant être appelé à distance pour calculer les sommes de contrôle sur la machine distante et répondre avec le hachage?

Idéalement, j'aimerais le déploiement à distance complet, mais j'ai accès à la machine distante pour l'installation et la configuration.

Les cibles sont Windows et Ubuntu/FreeBSD utilisant Mono.

Modifier

Je ne me suis pas expliquer aussi bien que je ne le pensais. J'ai un serveur qui héberge un grand nombre de gros fichiers et plutôt que de diffuser ces fichiers sur le réseau de mon ordinateur personnel pour calculer la somme de contrôle (comme je l'ai été) je cherche un moyen d'exécuter un démon sur le serveur Je peux demander de calculer la somme de contrôle pour un fichier qu'il héberge localement et donnez-moi le hash.

+0

Avez-vous envisagé d'utiliser TcpClient et TcpListener pour envoyer les données ou effectuer les appels à distance? – MasterXD

+0

Je n'ai encore rien essayé mais je vais regarder TcpClient/Listener. Ce dont je suis le plus confus est de savoir comment démarrer le programme distant et lui transmettre des informations. Est-ce que cela doit être exécuté en tant que service/en arrière-plan? – Michael

+0

Il ne doit pas être en arrière-plan, mais c'est une bonne idée. J'utilise backgroundWorkers pour établir la connexion entre le "client" et le "serveur". Je peux laisser une réponse expliquant comment faire cela, est-ce que ça sonne bien? Si oui, le processus ressemble-t-il à ceci: "Send checksum -> Counterpart calcule -> Recieve checksum"? – MasterXD

Répondre

0

Et maintenant une réforme complète de la réponse. Tout en continuant à commenter aussi bien que je le pouvais, j'ai essayé de le garder aussi "basique"/"général" que possible sans créer de petits détails.


programme principal (méthode normale)

public async Task<byte[]> ConnectToCounterpart(string dataToSend) 
{ 
    // === Sending empty strings breaks the program === 
    if (String.IsNullOrEmpty(dataToSend)) 
     return null; 


    // === Variables n' Stuff === 
    string counterPartIP = "127.0.0.1"; // The ip of the computer running counterpart program. (127.0.0.1 is the localhost/current computer). 
    int counterPartPort = 50_000; // The port which the counterpart program listens to 


    // === Getting a connection === 
    TcpClient client = new TcpClient(counterPartIP, counterPartPort); // Connect to the counterpart program 

    NetworkStream nwStream = client.GetStream(); // Get the networkStream between the main and counterpart program 
    nwStream.ReadTimeout = 5_000; // Give the counterpart program 5 seconds to do its thing 


    // === Convert the "dataToSend" to a byte-array === 
    byte[] bytesToSend = Encoding.UTF7.GetBytes(dataToSend); // An array with the bytes of the string (UTF7 lets you keep "cpecial characters like Æ, Ø, Å, Á etc.") 


    // === Send the file-bytes === 
    await nwStream.WriteAsync(bytesToSend, 0, bytesToSend.Length); // Send the file-bytes to the counterpart program 


    // ========================================== 
    // At this point counterpart is doing work 
    // ========================================== 


    byte[] returnBytes = new byte[client.ReceiveBufferSize]; // The byte-array this method returns 
    try 
    { 
     // === Recieve the reply === 
     int numberOfBytesRecieved = await nwStream.ReadAsync(returnBytes, 0, client.ReceiveBufferSize); // Receve the checksum from the counterpart and tthe ammount of sent bytes 


     // === Crop return-array to the recieved bytes === 
     Array.Resize(ref returnBytes, numberOfBytesRecieved); 
    } 
    catch (Exception ex) 
    { 
     MessageBox.Show(ex.ToString(), "Error while retrieving"); // Show error 

     returnBytes = null; // Set returnbytes to null 
    } 


    // === Close and dispose stream === 
    nwStream.Close(); 
    nwStream.Dispose(); 


    // === Return the byte-array === 
    return returnBytes; 
} 

Dans ce morceau de code que vous avez sans doute remarqué "async", "Task<byte[]>" et "await". "Task<byte[]>" est le même que "byte[]" (un peu) et est utilisé parce que le modificateur "async" l'exige. (À propos de la programmation asynchrone: https://msdn.microsoft.com/da-dk/library/hh156513(v=vs.110).aspx)

Le type renvoyé sera dans tous les cas toujours "octet []". "Async" et "Await" seront expliqués plus loin dans un "bit" (Byte, bit ... Puns).

Code Contrepartie (BackgroundWorker)

private void BackgroundWorkerCalculate_Counterpart_DoWork(object sender, DoWorkEventArgs e) 
{ 
    // === Variables n' Stuff === 
    int listeningPort = 50_000; // The port which the counterpart program listens to 


    // === Start listening === 
    TcpListener listener = new TcpListener(IPAddress.Any, listeningPort); // Listen to the port 
    listener.Start(); 


    // Infinite loop for infinite computations 
    while (true) 
    { 
     // === Getting a connection === 
     TcpClient connection = listener.AcceptTcpClient(); 
     NetworkStream nwStream = connection.GetStream(); 


     // === Get the recieved bytes === 
     byte[] recievedBytes = new byte[connection.ReceiveBufferSize]; // Create a buffer for the incomming file-bytes 
     int numberOfBytesRecieved = nwStream.Read(recievedBytes, 0, connection.ReceiveBufferSize); // Read the bytes to the buffer 


     // === Convert recieved bytes to a string === 
     string recievedString = Encoding.UTF7.GetString(recievedBytes, 0, numberOfBytesRecieved); 



     // === Understanding the recieved data === 
     /* Lets say recievedString == "[path]" */ 

     byte[] replyBytes = new byte[] { 1 }; // Bytes to reply to the main program 

     try 
     { 
      using (MD5 md5 = MD5.Create()) // Create the hashing protocol 
      { 
       using (FileStream fileStream = new FileStream(recievedString, FileMode.Open)) // Open the file to hash 
       { 
        replyBytes = md5.ComputeHash(fileStream); // replyBytes now contains the hash 
       } 
      } 
     } 
     catch 
     { } // If file doesn't exist, then replyBytes stays as { 1 }, which will be returned if things goes wrong 


     // === Send the reply to main program === 
     nwStream.Write(replyBytes, 0, replyBytes.Length); 
    } 
} 

Ce code fait toujours le même: certaines données et recieves retourne des données. Vous pouvez maintenant modifier la partie "Comprendre les données reçues" selon vos besoins. Par exemple, vérifier si le chemin reçu est un fichier ou un répertoire, différenciant ainsi "GetChecksum" (se référant à un fichier) et "GetSubelements" (se référant à un répertoire).

Programme principal (Usage)

private async void ButtonCalculate_Counterpart_Click(object sender, EventArgs e) 
{ 
    // This is how you use the method 
    byte[] replyBytes = await ConnectToCounterpart(@"folder\file.txt"); 

    // "async" makes the given method "asyncronous", so that it runs parallell to other tings 
    // "await" will prevent a time-consumeing method-call from "halting" or "blocking" the main process. 


    // Check if things went wrong 
    if (replyBytes == new byte { 1 }) // As mentioned ealier in the backgroundWorker code 
    { 
     MessageBox.Show("Something went wrong with the hashing. Is the path correct?", "Could not hash") 
     return; 
    } 


    // If you want the reply as a normal string 
    string replyString = Encoding.UTF7.GetString(replyBytes, 0, replyBytes.Length); 

    // If you want the reply as a checksum 
    string checkSum = BitConverter.ToString(replyBytes); 
} 

Les commentaires ici devraient expliquer les choses.


Remarque: Vous pouvez facilement utiliser d'autres types de chiffrement que UTF7, mais soyez cohérent dans le code.

Note 2: Si les données envoyées dépassent 50 Ko, il y a un risque que toutes les données ne soient pas envoyées, à cause de la façon dont j'ai programmé cela.Si cela devient un problème, je peux faire quelques changements. Ces changements sont simplement plus compliqués.

Remarque 3: Si vous souhaitez accéder à la contrepartie d'un réseau distinct (sur Internet et non localement), vous devrez effectuer une redirection de port sur le routeur auquel le compteur est connecté.

Note 4: N'oubliez pas que si vous passez un chemin comme celui-ci "Folder\File.txt" à la contrepartie, alors la contrepartie regardera le répertoire "C:\Users\...\...\FolderWithProgramExe\Folder\File.txt". Si vous passez plutôt "C:\Folder\File.txt" (notez "C:\" au début) à la contrepartie, alors l'homologue se penchera exactement sur l'emplacement "C:\Folder\File.txt" sur l'ordinateur.

J'espère que cela vous sera utile maintenant. Comme je l'ai dit, j'ai essayé de garder le code aussi "plastique"/"facilement modifiable" que possible, afin que vous puissiez l'ajuster à vos besoins.

+0

Pas tout à fait mais le code TCP est génial pour me faire la tête (jamais fait de programmation réseau avant). Je ne me suis pas expliqué aussi bien que je le pensais. L'idée est que j'ai un serveur qui héberge un grand nombre de gros fichiers et plutôt que de diffuser ces fichiers sur le réseau sur mon ordinateur pour calculer la somme de contrôle (comme je l'ai été) je cherche un moyen d'exécuter un démon sur le serveur que je peux demander de calculer la somme de contrôle pour un fichier qu'il héberge localement et donnez-moi le hachage. Les hachages C# sont retournés comme octets [], pour obtenir une chaîne hexadécimale que vous appelez BitConverter.ToString (octet []) ou bouclez-la vous-même – Michael

+0

@Michael Oooooohhhhh. Je vois maintenant. Voulez-vous identifier le fichier par nom de fichier, un ID pour le fichier ou via une liste que vous pouvez diffuser à partir de la contrepartie? Est-ce que l'homologue garde une trace des fichiers pouvant être traités ou est-ce que vous mettez juste beaucoup de fichiers dans un seul dossier? – MasterXD

+0

En ce moment, je pense que je passerais un chemin à partir d'un partage connu que la télécommande serait mis en place pour déréférencer. Mais je suis ouvert à ça s'il y a un meilleur moyen. – Michael