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.
Avez-vous envisagé d'utiliser TcpClient et TcpListener pour envoyer les données ou effectuer les appels à distance? – MasterXD
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
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