2012-07-29 13 views
17

Jest to problem, który badałem w zeszłym tygodniu i nie mogę znaleźć rozwiązania. Znaleziono posty z prośbą o to samo, ale nigdy nie otrzymuję odpowiedzi, mam nadzieję, że to pomoże także innym.Jak przerwać strumień z usługi WCF bez czytania do końca?

Mam usługę WCF, która zwraca obiekt zawierający w środku stream. Używam basicHttpBinding z przesyłaniem strumieniowym i Mtom, aby wysłać je do klienta.

Klient wywołuje usługę WCF i zamyka serwer proxy natychmiast po otrzymaniu obiektu odpowiedzi.

Następnie klient odczytuje strumień pobrany z usługi WCF i zapisuje go w pliku na dysku lokalnym. Wszystko to działa dobrze.

Mój problem polega na tym, że klient chce przerwać operację i przestać pobierać dane z usługi WCF. Jeśli wywołam .close() w strumieniu, np .: serverReply.DataStream.Close();, to blokuje i odczytuje cały strumień z usługi WCF do końca przed kontynuowaniem. Strumień może być dość duży, a sieć nie zawsze jest szybka.

Jest to bardzo niepożądane w przypadku wykorzystania zasobów sieciowych, które są w zasadzie marnowane na dane, które już nie są potrzebne. A ponieważ basicHttpBinding zezwala tylko na dwa równoczesne połączenia TCP (domyślnie) z serwerem usługi WCF, blokuje inne próby połączenia, dopóki strumień nie zostanie odczytany do końca.

Mogłabym zwiększyć liczbę jednoczesnych połączeń, ale byłoby to złe rozwiązanie, ponieważ spowodowałoby to kłopot.

Na przykład 20 przerwanych pobrań, które wciąż pobierają dane, aby je wyrzucić. Muszę sprawić, żeby transfer całkowicie się zatrzymał.

Na kliencie obiekt strumieniowy jest zwykłą klasą Stream, więc zawiera tylko metodę ścisłą, nic więcej.

Wywołanie .close() lub na obiekcie proxy nie pomaga, ani nie niszczy go za pomocą .dispose() lub jakiejkolwiek innej metody. Po stronie serwera obsługuję zdarzenie OperationContext.OperationCompleted, ale nie jest ono wywoływane, dopóki dane z stream nie zostaną odczytane do końca.

Pytanie brzmi: jak zamknąć/przerwać transmisję bez jej całkowitego przeczytania?

+0

Czy to szczęście? – Schultz9999

+0

Cierpienie z tym samym problemem podczas wysyłania naprawdę dużych plików ... wydaje się, że brakuje czegoś naprawdę oczywistego. prawdopodobnie będę musiał wdrożyć chunking jako obejście tego problemu. –

Odpowiedz

0

Czy próbowałeś już grać z ?
Czy próbowali zabawy ze swoimi app.config ustawień pliku np:

<bindings> 
    <wsHttpBinding> 
    <binding name="default" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647" 
      closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" > 
     <readerQuotas maxArrayLength="2147483647" maxBytesPerRead="4096" maxNameTableCharCount="16384" 
        maxDepth="64" maxStringContentLength="2147483647" /> 
    </binding> 

    </wsHttpBinding> 
</bindings> 

chciałbym zminimalizować timeoutów ANF długości bufora i starają się przerwać lub blisko i zobaczyć co się dzieje.

+1

Próbowałem, ale to nie pomaga. Gdy serwer rozpocznie wysyłanie strumienia, nie zatrzymuje się, dopóki nie zostanie odebrany przez klienta. Zamknięcie proxy nic nie robi. To tak, jakby nie było żadnego wyraźnego sposobu na powstrzymanie komunikacji. Gdy klient przestaje czytać strumień, widzę okno zerowe z powrotem do serwera. Serwer okresowo wysyła sondę zerową do okna, aby sprawdzić, czy klient jest gotowy do ponownego przeczytania. I oczywiście klient ponownie odsyła okno zerowe. To trwa wieczność, dopóki proces nie zostanie zabity. – Yev

+0

Czy próbowałeś czytać strumień przy użyciu tylko klasy HttpClient i sprawdzając, czy możesz zamknąć strumień? –

+0

Jak to zrobić bez wywoływania usługi WCF? Zrobiłem więcej badań i wydaje się, że nie ma sposobu, aby zamknąć strumień od strony klienta. Próbowałem innego podejścia. Stworzyłem inną usługę, usługę kontrolną i próbowałem zamknąć strumień stamtąd (po stronie serwera). Ale bez powodzenia. Coś po prostu nie działa, nie zamyka się ani nie likwiduje. – Yev

1

Po przeprowadzeniu dochodzenia odkryłem, że klient WCF będzie kontynuował czytanie ze strumienia, dopóki nie zakończy się termin closeTimeout, a następnie przerwie połączenie. Możesz zmniejszyć closeTimeout na kliencie, aby zminimalizować problem.

UWAGA: Powinieneś owinąć kod, który zrzuca strumień do bloku try/catch. Metoda stream.Dispose() będzie generować wyjątek TimeoutException, który hamuje wytyczne not throwing exceptions in Dispose method.

0

Myślę, że po prostu otrzymujesz bufor po zamknięciu. Powinieneś ustawić maxBufferSize na mniejszą wartość.

Możesz również chcieć ograniczyć ilość danych odczytanych na serwerze, zawijając strumień i przesyłając odczyt. Użyj mniejszych porcji, jeśli masz klienta o niskiej przepustowości i zwróć odpowiednią liczbę z metody odczytu, aby dopasować ją do faktycznie przeczytanej ilości. To ograniczyłoby współczynnik wypełnienia bufora.

Moje własne testy na ten temat wymagały pisania zawsze NeverEndingStream i zwracania danych. W pewnym momencie zadzwoniłem blisko do klienta, a prawie natychmiast zamknięcie zostało wywołane na serwerze. Sugeruje to, że bufor został po prostu opróżniony, ponieważ wyraźnie nie byłby w stanie odczytać mojego strumienia do końca.

Jeśli nadal występują problemy, sugeruję, aby śledzić czas odczytywania metody na przesłoniętym strumieniu. Jeśli currentReadtime - lastReadTime jest> x, możesz zamiast tego wywołać Close i wygenerować wyjątek. To na pewno ją zabije.

Powiązane problemy