0

从 C# 中的一个小型文件传输套接字应用程序开始(目前主要是 MS 示例代码)。ManualResetEvent.WaitOne() 遇到问题。我在foreach 循环中调用它,所以也许这就是问题所在。
无论如何,我都在尝试订购/阻止 BeginSend 调用,以便它们在文件传输成功后启动。但似乎即使我在每次 BeginSend 之后调用 WaitOne() ,它们也会出现故障。

这是一个示例:

public class AsynchronousClient {

// ManualResetEvent instances signal completion.
private static ManualResetEvent connectDone = 
    new ManualResetEvent(false);
private static ManualResetEvent sendDone = 
    new ManualResetEvent(false);
private static ManualResetEvent receiveDone = 
    new ManualResetEvent(false);

...

private static void SendAll(Socket client, String path)
{
    String[] files = GetFiles(path);

    int i = 0;
    foreach(String file in files){
        Console.WriteLine("STEP 1 - Files left: {0}", files.Length - i);
        SendFile(client, Path.GetFullPath(file), files.Length - i);
        sendDone.WaitOne();        

        i++;
    }
}

private static void SendFile(Socket client, String path, int FilesLeft )
{
    byte[] filesLeft = BitConverter.GetBytes((Int64)FilesLeft);
    byte[] fileData = File.ReadAllBytes(path);
    byte[] fileLength = BitConverter.GetBytes((Int64) fileData.Length);
    byte[] fileMD5;

    using (MD5 md5Hash = MD5.Create())
    {
        fileMD5 = md5Hash.ComputeHash(fileData);
    }

    byte[] filepathdata = Encoding.Unicode.GetBytes(path);
    byte[] filepathLength = BitConverter.GetBytes((Int16)filepathdata.Length);

    byte[] byteData = filesLeft.Concat(fileLength).Concat(fileMD5).Concat(filepathLength).Concat(filepathdata).Concat(fileData).ToArray();

    Console.WriteLine("STEP 2 - File length: {0}", fileData.Length);

    // Begin sending the data to the remote device.
    client.BeginSend(byteData, 0, byteData.Length, 0,
        new AsyncCallback(SendCallback), client);
}

private static void SendCallback(IAsyncResult ar)
{
    try
    {
        // Retrieve the socket from the state object.
        Socket client = (Socket)ar.AsyncState;

        // Complete sending the data to the remote device.
        int bytesSent = client.EndSend(ar);
        Console.WriteLine("STEP 3 - Sent {0} bytes to server.", bytesSent);

        // Signal that all bytes have been sent.
        sendDone.Set();
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
    }
}

...这是(不)步骤的顺序:

STEP 1 - Files left: 16
STEP 2 - File length: 432759
STEP 3 - Sent 433033 bytes to server.
STEP 1 - Files left: 15
STEP 2 - File length: 262623
STEP 1 - Files left: 14
STEP 3 - Sent 262897 bytes to server.
STEP 2 - File length: 459683
STEP 1 - Files left: 13
STEP 2 - File length: 369381
STEP 1 - Files left: 12
STEP 2 - File length: 271126
STEP 1 - Files left: 11
STEP 3 - Sent 459957 bytes to server.
STEP 3 - Sent 369679 bytes to server.
STEP 2 - File length: 1647983
STEP 1 - Files left: 10
STEP 2 - File length: 24761
STEP 1 - Files left: 9
STEP 3 - Sent 25049 bytes to server.
STEP 3 - Sent 271424 bytes to server.
STEP 2 - File length: 858717
STEP 1 - Files left: 8
STEP 2 - File length: 214031
STEP 1 - Files left: 7
STEP 2 - File length: 531963
STEP 1 - Files left: 6
STEP 2 - File length: 227950
STEP 1 - Files left: 5
STEP 2 - File length: 394068
STEP 1 - Files left: 4
STEP 2 - File length: 243546
STEP 1 - Files left: 3
STEP 2 - File length: 173656
STEP 1 - Files left: 2
STEP 2 - File length: 712417
STEP 1 - Files left: 1
STEP 3 - Sent 1648279 bytes to server.
STEP 2 - File length: 1631924
STEP 3 - Sent 859001 bytes to server.
STEP 3 - Sent 214309 bytes to server.
STEP 3 - Sent 532239 bytes to server.
STEP 3 - Sent 228226 bytes to server.
STEP 3 - Sent 394346 bytes to server.
STEP 3 - Sent 243822 bytes to server.
STEP 3 - Sent 173936 bytes to server.
STEP 3 - Sent 712701 bytes to server.
STEP 3 - Sent 1632220 bytes to server.
ReceiveCallback: bytesRead <= 0
Response received : OK

问题是:即使步骤无序,文件数据在服务器端也是完整的。在完成之前多次调用 BeginSend 似乎是可行的,但我仍然希望在开始另一次传输之前等待文件通过服务器。

4

2 回答 2

0

ManualResetEvent就像名字告诉我们的那样:它必须手动重置!

手动重置事件就像门。当事件没有发出信号时,等待它的线程将阻塞。当事件发出信号时,所有等待的线程都被释放,并且事件保持有信号状态(即后续的等待不会阻塞),直到调用它的 Reset 方法。当一个线程必须在其他线程可以继续之前完成一项活动时,手动重置事件很有用。

自动重置事件提供对资源的独占访问。如果在没有线程等待的情况下发出自动重置事件,则它会一直发出信号,直到有线程尝试等待它为止。该事件释放线程并立即重置,阻塞后续线程。

(来源:http: //msdn.microsoft.com/en-us/library/system.threading.eventwaithandle.aspx

出于您的目的,AutoResetEvent应该适合。

进一步说明: 在您的示例中,它等待第一个Set(),然后门打开,并且以下所有内容WaitOne()都可以通过,因为没有人关闭门。

于 2013-09-09T15:11:10.757 回答
0

如果可以,您应该考虑使用 Web 服务。在客户端/服务器之间双向发送/流式传输文件有很好的嵌入式功能。

于 2013-09-09T14:22:38.060 回答