2012-01-26 10 views
7

Próbuję zrozumieć klasy "SocketAsyncEventArgs" w języku C#. http://msdn.microsoft.com/en-us/library/system.net.sockets.socketasynceventargs.aspxC# SocketAsyncEventArgs obsługa odbierania i wysyłania danych

śledzę ten tutorial: http://www.codeproject.com/Articles/83102/C-SocketAsyncEventArgs-High-Performance-Socket-Cod

Teraz siedzę w jaki sposób dokładnie należy przetwarzać dane z mojego serwera. Próbuję użyć SocketAsyncEventArgs dla podłączonego klienta z przydzielonym obszarem bufora o wielkości 512 bajtów w buforze BufferManager. Następnie chcę odszyfrować dane z bajtu [] do mojej własnej klasy niestandardowej (ClientPacket), która przechowuje bajt [] do dekodowania i odczytu.

To wszystko jest dobrze, ale mój serwer nie zawsze odpowie dane pytanie brzmi:

używać 1 SocketAsyncEventArgs dla odbioru i pętli wokół przetwarzać odbierać dane, a następnie przydzielić do SocketAsyncEventArgs z puli ilekroć Muszę wysłać, a następnie zwrócić po zakończeniu?

A jak SocketAsyncEventArgs wie, kiedy czytanie jest zakończone? (gdy skończy się z buforem bajtowym [], zanim nadpisze go z nowymi danymi), np. w jaki sposób jest on zwracany do puli, gdy jest to zrobione, jeśli nie odpowiem z powrotem?

Odpowiedz

8

Używam tylko jednej instancji SocketAsyncEventArgs dla wszystkich moich potrzeb. Po prostu resetuję bufor między każdym żądaniem (ustawiając go na nowy bajt []).

Raz podłączone i mają odniesienie do gniazda, to rozpocząć odtwarzanie tak:

public void StartListening(SocketAsyncEventArgs e) 
{ 
    ResetBuffer(e); 
    e.Completed += SocketReceive; 

    socket.ReceiveAsync(e); 
} 

mam funkcji pomocnika, który zeruje bufor:

private void ResetBuffer(SocketAsyncEventArgs e) 
{ 
    var buffer = new Byte[SocketBufferSize]; 

    e.SetBuffer(buffer, 0, SocketBufferSize); 
} 

przetwarzać dane na przykład:

private void SocketReceive(Object sender, SocketAsyncEventArgs e) 
{ 
    ProcessData(e.Buffer, 0, e.BytesTransferred); 

    ResetBuffer(e); 

    socket.ReceiveAsync(e); 
} 

W ProcessData można użyć tablicy bajtów, aby pobrać dane . Używam go do tworzenia MemoryStream które następnie deserializowania w mojej klasie (podobny do ClientPacket), w następujący sposób:

private void ProcessData(Byte[] data, Int32 count) 
{ 
    using (var stream = new MemoryStream(data, 0, count)) 
    { 
     var serializer = new XmlSerializer(typeof(ClientPacket)); 

     var packet = serializer.Deserialize(stream); 

     // Do something with the packet 
    } 
} 

Co do ostatniego pytania. Ramy obsługują wszystko, co ma związek z podstawowym protokołem TCP itp., Więc można polegać na wywoływaniu programu obsługi zdarzeń za każdym razem, gdy istnieją dane do przetworzenia. Użyj wartości e.BytesTransferred, aby wskazać ilość faktycznie otrzymanych danych, która może być mniejsza niż, ale nigdy nie przekroczy twojego rozmiaru bufora (SocketBufferSize w moim kodzie). Jeśli wiadomość była większa niż rozmiar bufora, infrastruktura TCP buforuje wiadomości i wysyła je do Ciebie w porcjach w oparciu o SocketBufferSize (podnosząc zdarzenie raz dla każdego fragmentu). Jeśli jest to problemem, po prostu zwiększ SocketBufferSize, aż większość wiadomości zostanie odebrana w jednym kawałku.

Wadą chunkingu jest to, że wiadomości mogą być łączone przez infrastrukturę, co oznacza, że ​​możesz potrzebować sposobu, aby określić, kiedy skończy się pierwsza wiadomość. Typowe podejścia obejmują poprzedzanie wiadomości czterobajtową liczbą całkowitą, która wskazuje długość komunikatu. W razie potrzeby mogę rozwinąć więcej.

Nadzieję, że pomaga.

+0

Powiedziałeś, ustawiając go na nowy bajt [], ale dzielę duży blok bufora na wszystkie SocketAsyncEventArgs, Jeśli odczytam z tego bloku bufora w pakiecie, blok bufora może zostać nadpisany przez następne przychodzące dane, nawet jeśli skopiuję tablicę bajtów [], to jest przeciwko użyciu bloku bufora do wysyłania/odbierania danych? W jaki sposób mogę wysłać dane z tym samym obiektem, gdy operacja odbierania może się zdarzyć w dowolnym momencie? –

+1

Wygląda na to, że zakładasz pojedyncze połączenie między dwoma komputerami. Nie można ponownie użyć tylko jednego SocketAsyncEventArgs podczas obsługi wielu równoczesnych połączeń, o czym moim zdaniem chodziło pytanie. (I na czym opiera się SocketAsyncEventArgs). –

+0

dzięki SonOfPirate, byłoby wspaniale, gdyby można było opracować więcej na odbieranie dużej ilości danych. w szczególności wyjaśnij proszę, czy muszę ponownie zadzwonić do ReceiveAsync za każdym razem, zanim dobiegnie końca; lub Framework zrobi to za mnie? –

Powiązane problemy