2010-04-23 10 views
12

Próbuję ponownie połączyć się z gniazdem, z którego się odłączyłem, ale z jakiegoś powodu nie pozwoli na to, mimo że nazwałem metodę Disconnect z argumentem "reuseSocket" ustawionym na true.Jak ponownie wykorzystać gniazdo w .NET?

_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
_socket.Connect(ipAddress, port); 
//...receive data 
_socket.Disconnect(true); //reuseSocket = true 
//...wait 
_socket.Connect(ipAddress, port); //throws an InvalidOperationException: 

Gdy gniazdo zostało odłączone, można podłączyć tylko raz asynchronicznie, a jedynie do innego punktu końcowego. BeginConnect musi być wywołany na wątku, który nie zakończy się aż do zakończenia operacji .

Co robię źle?

+0

Prawdopodobnie nie należy ponownie używać gniazda i po prostu utworzyć nowe. Nigdy nie dzwoń do 'Disconnect', zamiast tego użyj' use'. Zadzwoń również do 'Shutdown'. – usr

Odpowiedz

3

Po przeczytaniu dokumentacji MSDN dla Socket.Disconnect zauważyłem coś, co może być przyczyną problemu.

Jeśli trzeba zadzwonić Disconnect bez pierwszego wywołującego Shutdown można ustawić SocketOption nazwie DontLinger do false niezerową i określić przedział czasowy, w celu zapewnienia, że ​​dane w kolejce do transmisji wychodzącej są wysyłane. Rozłącz następnie blokuj do momentu wysłania danych lub do wygaśnięcia określonego czasu. Jeśli ustawisz DontLinger na false i określisz limit czasu zerowania, Close zwalnia połączenie i automatycznie odrzuca wychodzące dane w kolejce.

spróbuj ustawić opcję DontLinger Socket i określić czas oczekiwania 0 lub użyć Shutdown przed wywołaniem odłączyć.

+1

Zabawne jest to, że nie ma takiej właściwości lub metody o nazwie "DontLingerSocket". Najbliższą rzeczą jest właściwość o nazwie "LingerState".Możesz jednak utworzyć "LingerOption" i ustawić na to, ale nie ma to znaczenia, jeśli spróbujesz połączyć się ponownie po wywołaniu "Disconnect". I nie można ponownie użyć gniazda, jeśli wywołasz "Zamknij", ponieważ spowoduje to usunięcie gniazda. –

+0

Tam zaginęła przestrzeń, powinny to być dwa słowa "DontLinger" i "Socket". Lepszym sposobem na wyrażenie tego zdania jest * "... wywołanie Shutdown, możesz ustawić [SocketOption] (http://msdn.microsoft.com/en-us/library/e160993d.aspx) o nazwie [DontLinger] (http : //msdn.microsoft.com/en-us/library/system.net.sockets.socketoptionname.aspx) na wartość false i podaj wartość niezerową ... "* –

+0

@ScottChamberlain należycie zaznaczono. – James

0

Od MSDN:

// Release the socket. 
client.Shutdown(SocketShutdown.Both); 

client.Disconnect(true); 
if (client.Connected) 
    Console.WriteLine("We're still connnected"); 
else 
    Console.WriteLine("We're disconnected"); 

Jeśli używasz protokołu połączeniowego, można użyć tej metody, aby zamknąć gniazdo. Ta metoda kończy połączenie i ustawia właściwość Connected na false. Jednak jeśli reuseSocket ma wartość true, możesz ponownie użyć gniazda.

Aby upewnić się, że wszystkie dane są wysyłane i odbierane przed zamknięciem gniazda, należy zadzwonić Shutdown przed wywołaniem metody Disconnect.

Socket.Shutdown Metoda czeka, aż wszystkie dane w buforze zostaną wysłane lub odebrane. Jeśli jednak ustawimy tylko opcje opóźnienia, gniazdo zostanie zamknięte po określonym czasie oczekiwania.

+0

Próbowałem tego, nie działa. –

+1

@Hermann: Myślę, że będziesz musiał poczekać kilka sekund (timeout), aby gniazdo mogło być "ponownie użyte", możesz spróbować włożyć swoje gniazdo do wątku - na próbę ... tylko myślenie; więcej informacji na temat 'graceful shudown', http://msdn.microsoft.com/en-us/library/ms738547(VS.85).aspx –

+0

UWAGA:' client.Connected' jest zdefiniowany jako stan połączenia od najnowsze "Wyślij" lub "Odbierz", a nie bieżący stan. A ponieważ właśnie nazwałaś "Rozłącz", wiadomości powinny brzmieć "" Byliśmy połączeni. "I" "Nie byliśmy połączeni" '. –

4

można ustawić opcje gniazda jak ten

_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, True) 

Jeśli to nie pomoże, spróbować innych opcji

_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, false) 
_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, True) 
_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 500) 
_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, Timeout) 
1

Czy warto dodać ten wiersz po rozłączeniu i przed podłączeniem?

client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
Powiązane problemy