TcpClient.Close не закрывает соединение - PullRequest
2 голосов
/ 02 февраля 2011

У меня есть приложение, которое использует TcpClient и TcpListener для связи по сети.Однако, когда я вызываю TcpClient.Close на клиенте, чтобы отключить его от сервера, сервер вообще не реагирует.

Теперь, прежде чем публиковать комментарий о том, что этот вопрос является дубликатом этот один, и как найти решение здесь , поверьте мне, когда я скажу, что я уже нашел их и попробовал.Это не помогаетЯ также пробовал разные комбинации TcpClient.Close, TcpClient.GetStream().Close() и TcpClient.Dispose.Ничего не работает.

В коде нет ничего примечательного, просто метод Disconnect в клиенте, который сбрасывает все переменные для повторного использования и закрывает все сетевые ресурсы.На сервере есть цикл, который проверяет, является ли TcpClient.Connected истинным или нет, и если он ложный, он должен выпрыгнуть из цикла и завершить поток.

Есть идеи?

Ответы [ 2 ]

8 голосов
/ 02 февраля 2011

TcpClient.Connected в значительной степени следует игнорировать.Это в основном показывает, было ли последнее сообщение успешным.От MSDN (выделено мной):

Поскольку свойство Connected отражает только состояние соединения на момент последней операции, вы должны попытаться отправить или получить сообщение дляопределить текущее состояние.После сбоя отправки сообщения это свойство больше не возвращает true.Обратите внимание, что это поведение предусмотрено дизайном.Вы не можете надежно проверить состояние соединения, потому что во время между проверкой и отправкой / получением соединение могло быть потеряно. Ваш код должен предполагать, что сокет подключен, и изящно обрабатывать неудачные передачи.

Если вы вызываете Close() на стороне клиента, ничего не отправляетсячтобы сервер сказал ему, что он закрывается, он буквально просто закрывает себя, чтобы клиент больше не мог его использовать.Единственный надежный способ определить, по-прежнему ли вы подключены, - это попытаться отправить данные и обработать ошибку.Если вы хотите, вы можете реализовать собственное соглашение о рукопожатии, когда при вызове Close() вы отправляете на сервер специальное уведомление, предупреждающее об этом, но все равно будут случаи, когда этот пакет никогда не достигнет сервера.

0 голосов
/ 04 июля 2013

Прослушайте один байт, если он получен, получите остальное. Если при получении одного байта возвращается 0, клиент отключен.

        IPAddress nReceiveAddress = IPAddress.Parse(GetIp(sSource));
        IPEndPoint localEndPoint = new IPEndPoint(nReceiveAddress, GetPort(sSource));
        Socket nSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        nSocket.Bind(localEndPoint);

        nSocket.Listen(10);
        Socket nSocketClient = nSocket.Accept();

                byte[] bufferOne = new byte[1];
                int nBytes = nClient.Receive(bufferOne);

                if (nBytes == 0)
                {
                    AppendToLog(String.Format("{0}: Closing.", sName));
                    nClient.Close();
                }
                else
                {
                    byte[] buffer = null;
                    buffer = new byte[nClient.Available + 1];

                    if (nClient.Available > 0)
                        nBytes = nClient.Receive(buffer);

                    if(nBytes>0)
                    {
                        //KS effectively insert the first received byte at start.
                        Array.Copy(buffer, 0, buffer, 1, buffer.Length - 1);
                        buffer[0] = bufferOne[0];
                    }
                }
...