2017-08-16 121 views
0

我已经编写了一个程序来生成文件校验和。一切工作正常在本地机器上,但速度很慢,并转向****当我分支出远程机器由于网络速度(显然)。如何编写可远程调用的对应程序以在远程计算机上执行计算

我该如何着手编写远程调用的对应程序来计算远程机器上的校验和并用散列做出响应?

理想情况下,我会喜欢完整的远程部署,但我有权访问远程机器进行安装和设置。

目标是使用Mono的Windows和Ubuntu/FreeBSD。

编辑

我没有解释我自己以及我以为。我有一个服务器托管大量的大文件,而不是通过网络将这些文件流到我的个人计算机来计算校验和(正如我一直),我正在寻找一种方法来在服务器上运行守护进程我可以要求计算它在本地托管的文件的校验和,并给我散列。

+0

您是否使用TcpClient和TcpListener来发送数据或进行远程调用? – MasterXD

+0

我还没有尝试过任何东西,但我会看看TcpClient/Listener。 我最困惑的是如何启动远程程序并将信息传递给它。它是否必须作为服务/在后台运行? – Michael

+0

它不必在背景中,但它是一个好主意。我使用backgroundWorkers建立“客户端”和“服务器”之间的连接。我可以留下一个答案解释如何做到这一点,这听起来不错?如果是的话,过程是这样的:“发送校验和 - >对应计算 - >接收校验和”? – MasterXD

回答

0

现在对答案进行了彻底改革。尽管仍然可以评论,但我尽可能保持它为“基本”/“一般”,而不会造成松散的结果。


主程序(通常的方法)

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

在这一段代码,你可能已经注意到 “async”, “Task<byte[]>” 和 “await”。 “Task<byte[]>”与“byte[]”(kinda)相同,因为“异步”修饰符需要它。 (关于异步编程:https://msdn.microsoft.com/da-dk/library/hh156513(v=vs.110).aspx

返回的类型在任何情况下仍然是“byte []”。 “异步”和“等待”将在“位”(Byte,bit ... Puns)中进一步解释。

对方码(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); 
    } 
} 

此代码仍然不相同:临危一些数据,并返回一些数据。您现在可以根据需要修改“了解收到的数据”部分。例如,检查接收的路径是文件还是目录,从而区分“GetChecksum”(指文件)和“GetSubelements”(指目录)。

主程序(用途)

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

这里要解释的东西的意见。


注意:您可以轻松地使用其他加密之外UTF7,只是througout的代码是一致的。注2:如果发送的数据大于50 kB,那么由于我编程的方式,存在不是所有数据都被发送的风险。如果这成为一个问题,我可以做一些改变。这些变化只是更复杂。注意3:如果你想从一个单独的网络(通过互联网而不是本地)访问对方,那么你需要在反向连接的路由器上做一些端口转发。注意4:请记住,如果您将类似“Folder\File.txt”这样的路径传递给对方,则对方将查看目录“C:\Users\...\...\FolderWithProgramExe\Folder\File.txt”。如果您将“C:\Folder\File.txt”(开头的“C:\”)传递给对方,则对方会在计算机上精确查看“C:\Folder\File.txt”的位置。

我希望这会对你有用。如上所述,我尽量保持代码为“塑料”/“易于修改”,以便您可以根据自己的需求进行调整。

+0

不是很完美,但TCP代码非常适合我的头脑(之前从未做过网络编程)。我没有像我想的那样解释自己。这个想法是我有一个服务器托管大量的大文件,而不是通过网络将这些文件流式传输到我的计算机来计算校验和(正如我一直),我正在寻找一种方法来运行守护进程服务器,我可以要求计算它在本地托管的文件的校验和并给我散列。 C#散列返回为byte [],以获得您调用BitConverter.ToString(byte [])的十六进制字符串或自行循环使用 – Michael

+0

@Michael Oooooohhhhh。我现在明白了。你想通过文件名,文件的id还是通过可以从对应的流中发送的列表来识别文件?对方是否跟踪可散列的文件,或者你是否将很多文件放在一个文件夹中? – MasterXD

+0

现在我想我会通过一个已知共享的路径,远程将被设置为取消引用。但如果有更好的方法,我会接受。 – Michael