2009-11-20 24 views
8

Mam obiekt TcpClient, który przesyła niektóre dane do serwera, używając jego podstawowej metody NetworkStream.Write(). Nich, mam:Jaki jest poprawny sposób zamknięcia połączenia TCP?

TcpClient server = new TcpClient(serverName, 50001); 

/* ... */ 

NetworkStream stream = server.GetStream(); 

Teraz, gdy przycisk jest wciśnięty, połączenie powinno zamknąć. Jaki jest właściwy sposób zamknięcia połączenia? Dokumenty MSDN mówią, że zamknięcie TcpClient (z .Close()) w rzeczywistości nie zamyka gniazda, tylko zasoby TcpClient (to przynajmniej sposób, w jaki rozumiałem dokumenty).

Czy zatem wykonanie następnego kodu poprawnie zamknęłoby połączenie?

stream.Close(); 
server.Close(); 

Czy to wystarczy, czy powinienem najpierw sprawdzić (jakoś), jeżeli strumień (lub serwer) może być zamknięty (w przypadku, gdy połączenie jest półotwarty lub coś) ...

Nawet więcej , NetworkStream.Close() Dokumenty MSDN stwierdza, że ​​zwalnia zasoby (nawet gniazda), więc może zamknięcie strumienia byłoby wystarczające, biorąc pod uwagę, że uniemożliwiam korzystanie z TcpClient po tym punkcie.

Jakie jest właściwe podejście?

Odpowiedz

6

Jak the docs powiedzieć:

Wywołanie tej metody ostatecznie doprowadzić do zamknięcia związanego Socket a także zamknąć powiązanych NetworkStream, który jest używany do wysyłania i odbierania danych, jeśli jeden został stworzony.

Tak więc server.Close(); wystarczy.

Najpierw zamknięcie NetworkStream nigdy nie zaszkodzi.

Nawiasem mówiąc, jeśli zdarzy ci się być pomocą TcpClient tylko w jednej metodzie, zawinąć je w using() rachunku, dzięki czemu masz pewność, Dispose() (odpowiednik Close()) nazywa się na niej, nawet jeśli wyjątki są wyrzucane etc

+1

Chyba zaufany IntelliSense zbyt dużo. Wyskakujące okienko dla TcpClient.Close() stwierdza: "Zrzuca instancję System.Net.Sockets.TcpClient bez zamykania podstawowego połączenia." Dziwna rzecz. Dzięki za odpowiedź. –

+0

Tak właśnie mówią dokumenty 3.0 (http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.close(VS.85).aspx) w pierwszym zdaniu ... ale potem trzecie zdanie mówi, że * to * zamyka Socket i NetworkStream. Dokumenty 3.5 (które wcześniej łączyłem) są spójne. Podejrzewam, że wiersz w dokumentach 3.0 był błędem. – Joren

0

Masz rację, zamykając strumień, a następnie serwer. Powinno to skutkować pomyślnym zamknięciem wszystkich gniazd w czasie, jak stwierdza dokumentacja. Jednak kilka błędów drapania głowy nauczyło mnie ważnej lekcji z biegiem czasu:

Nie zapomnij spłukać!

stream.Flush(); 
stream.Close(); 
server.Close(); 

Będziesz często tracić dane, które według Ciebie inaczej wysłałeś. Pomaga to również zapewnić, że strumień powinien być pusty i nieaktywny po jego zamknięciu.

+9

Z dokumentów w NetworkStream: "Metoda Flush implementuje metodę Stream.Flush, jednak ponieważ obiekt NetworkStream nie jest buforowany, nie ma wpływu na strumienie sieciowe. Wywołanie metody Flush nie powoduje wyjątku." Więc nie ma znaczenia, czy spuszczasz strumień, czy nie. – Joren

3

Powiążę połączenie TCP z gniazdem.

Generalnie procedura jest tak: 1. Wykończenie wysyłania danych 2. Zaproszenie Socket.Shutdown parametrem SocketShutdown.Send 3. Pętla podczas odbierania aż zwraca 0 lub nie z wyjątkiem 4.Zadzwoń Close()

Oto mała próbka w pseudo kod, który jest bardzo podobny do C# :)

void CloseConnection(Socket socket) 
{ 
    socket.Send(/*last data of the connection*/); 
    socket.Shutdown(SocketShutdown.Send); 

    try 
    { 
     int read = 0; 
     while((read = socket.Receive(/*application data buffers*/)) > 0) 
     {} 
    } 
    catch 
    { 
     //ignore 
    } 
    socket.Close(); 
} 

Jeżeli pierwszy i trzeci etapy są pomijane - utrata danych może się zdarzyć.

Zrobione z How to close TCP socket

+0

Właśnie tego potrzebowałem, dzięki! W moim przypadku pozostałe odpowiedzi nie działały. Możliwe, że w niektórych przypadkach nie odczytałem wszystkich dostępnych danych od klienta (w niektórych przypadkach zwrócę błąd przed odczytaniem wszystkich danych, a następnie zamknę połączenie). Za pomocą tej metody rozpoczyna się wyłączanie, a następnie odczytuje również inne dane oczekujące. – eselk

Powiązane problemy