2011-08-24 8 views
6

Aktualnie testuję bibliotekę sieci zarządzanej C#, którą napisałem i natknąłem się na sporadyczny problem. Ten problem manifestuje się jako bardzo spójny (zawsze w obrębie 30ms) blok 5000ms w obiekcie networkstream.write(), który może stanowić 1% wszystkich operacji wysyłania. Jest to środowisko testowe, wszystkie działające lokalnie, za każdym razem używające dokładnie tego samego rozmiaru pakietu (2 MB). Na koniec klient ja ciągle pisać następujące do podłączonego NetworkStream:Problem z blokowaniem Networkstream.Write()

tcpClientNetworkStream.Write(headerBytes, 0, headerBytes.Length); 
tcpClientNetworkStream.Write(dataBytes, 0, dataBytes.Length); 

i na koniec serwera używam asynchronicznego odczytu czeka na dane. Po wyświetleniu danych używam pętli while przez tcpClientNetworkStream.DataAvailable, dopóki wszystkie dane nie zostaną odebrane.

Mam świadomość, że funkcja networkstream.write() może blokować, jeśli bufory są pełne, ale jeśli jest to problem, nie mogę wymyślić szybszego sposobu ich usunięcia po stronie serwera (wielkości buforów wysyłania i odbierania są domyślne przy 8192 bajtach). Fakt, że blok jest tak spójny, wydaje się bardzo dziwny. Moją pierwszą myślą była prawdopodobnie jakaś forma Thread.Sleep, ale wykonanie pełnego wyszukiwania projektu nie pokazuje żadnego. Jeśli ktokolwiek mógłby pomóc rzucić trochę światła na tę kwestię, która byłaby bardzo ceniona.

Marc

edit dodać: hack, która wydaje się mieć problem odejść jest następujący (chociaż nie jest związana wydajność hit ze względu na BlockCopy):

byte[] bytesToSend = new byte[headerBytes.Length + dataBytes.Length]; 
Buffer.BlockCopy(headerBytes, 0, bytesToSend, 0, headerBytes.Length); 
Buffer.BlockCopy(dataBytes, 0, bytesToSend, headerBytes.Length, dataBytes.Length); 
tcpClientNetworkStream.Write(bytesToSend, 0, bytesToSend.Length); 

edycja ADD2 : Powieliłem też problem, używając dwóch asynchronicznych zapisów z sygnałem wątku między tymi dwoma. W tej chwili jedynym rozwiązaniem, jakie mam, jest pojedyncza operacja zapisu, jak w powyższej edycji.

edytuj, aby dodać3: Ok, kolejna możliwa poprawka następuje. Nadal jestem zainteresowany tym, dlaczego sukcesywny zapis czasami "blokuje" sposób, w jaki to robi.

BufferedStream sendStream = new BufferedStream(tcpClientNetworkStream); 
sendStream.Write(bytesToSend, 0, bytesToSend.Length); 
sendStream.Write(packet.PacketData, 0, packet.PacketData.Length); 
sendStream.Flush(); 

edycja ADD4: Po dalszych intensywnych testów rozwiązania w „Edit do ADD3” nie sprawiają, że problem znika, po prostu zmniejsza występowanie do około 0,1% od wysyła. O wiele lepsze, ale dalekie od rozwiązania. Zamieniam asynchroniczny odczyt na blokujący czytać obok, żeby zobaczyć, czy to sortuje, jak sugeruje PaulF.

+0

Napisz więcej kodu, jak skąd pochodzą daneBytes? Czy jest gdzieś buforowany? – EKS

+0

Przepuszczam obiekt pakietowy do metody SendPacket(), która zawiera powyższe metody NetworkStream.Write(). Gdy ten obiekt pakietu zostanie utworzony poza SendPacket(), zawiera tablice bajtów dla "headerBytes" i "dataBytes". – MarcF

+0

Jestem ciekawy, czy problem nadal występuje, jeśli używasz synchronicznych (blokujących) odczytów po stronie serwera. – PaulF

Odpowiedz

2

Ok, brak konkretnych odpowiedzi na to pytanie, więc zrobię co w mojej mocy, aby samemu przedstawić mały wniosek. Domyślam się, że ten problem został pierwotnie spowodowany, ponieważ wypełniałem bufor tcp szybciej, niż to czyściłem. Jeśli bufor jest wypełniony, przed próbą dodania kolejnych danych istnieje pewien nieznany czas oczekiwania. Ten problem byłby prawdopodobnie najbardziej widoczny podczas wysyłania i odbierania danych w obrębie tej samej maszyny. Należy pamiętać, że domyślny rozmiar bufora odczytu w .net wynosi tylko 8192 bajtów, więc jeśli piszesz w znacznie większych porcjach, być może rozważ rozszerzenie tego rozmiaru bufora odczytu na coś większego, na przykład 512000 bajtów. Jednak samo w sobie powoduje inne problemy ze względu na dużą stertę obiektów itp., Ale jest to potencjalnie dyskusja na inne pytanie.