2013-09-09 4 views
0

Начиная с небольшого приложения сокетов для передачи файлов в C# (в основном, пример кода MS). Возникли проблемы с ManualResetEvent.WaitOne(). Я называю это внутри foreach loop, так что, возможно, это проблема.
В любом случае я пытаюсь заказать/заблокировать вызовы BeginSend, чтобы они начали после успешной передачи файла. Но кажется, что, хотя я вызываю WaitOne() после каждого BeginSend, они выходят из строя.Передача файла сервера клиента

Вот пример:

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, прежде чем он закончится, но я бы предпочел, чтобы дождался, когда файл перейдет на сервер, прежде чем начать новую передачу.

+0

Как вы создаете экземпляр 'ManualResetEvent'? можете ли вы добавить фрагмент кода? –

+0

Я добавил код для экземпляра ManualResetEvent. – steakoverflow

ответ

0

ManualResetEvent ведет себя точно так же, как говорит нам имя: его необходимо сбросить вручную!

Мероприятия с ручным сбросом напоминают ворота. Когда событие не сигнализируется, потоки, которые ждут от него, блокируются. Когда событие сигнализируется, все ожидающие потоки освобождаются, и событие остается сигналом (то есть последующие ожидания не блокируются), пока не будет вызван его метод Reset. События ручного сброса полезны, когда один поток должен завершить операцию до того, как другие потоки могут продолжить.

События автоматического сброса предоставляют эксклюзивный доступ к ресурсу. Если событие автоматического сброса сигнализируется, когда нити не ожидают, он остается сигнализированным, пока поток не попытается подождать. Событие освобождает поток и немедленно сбрасывается, блокируя последующие потоки.

(Источник: http://msdn.microsoft.com/en-us/library/system.threading.eventwaithandle.aspx)

Для вашей цели AutoResetEvent должен соответствовать.

Далее Explenation: В вашем примере, он ждет первого Set(), то ворота открыты, и все следующие WaitOne() может просто передать, как никто не закрывает ворота.

0

Если вы можете, вы должны подумать об использовании веб-службы. Есть очень хорошие встроенные функции для отправки/потокового файла между клиентом/сервером в обоих направлениях.