Закрытие System.Net.Sockets.TcpClient уничтожает соединение для других TCPClient с тем же IP-адресом - PullRequest
3 голосов
/ 08 февраля 2012

Просто чтобы прояснить, все TCPClients, на которые я ссылаюсь здесь, не являются экземплярами моего собственного класса, они все являются экземплярами System.Net.Sockets.TcpClient из реализации Mono .NET 4.0.

У меня есть сервер, который прослушивает подключения клиентов, как и серверы. Всякий раз, когда он получает нового клиента, он создает новый TCPClient для обработки соединения в новом потоке. Я отслеживаю все связи и темы со словарем. Если клиент отключается, он отправляет сообщение об отключении на сервер, TCPClient закрывается, словарная запись удаляется, и поток умирает естественным образом. Нет суеты, нет суеты. Сервер может обрабатывать несколько клиентов без проблем.

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

Поэтому я пытаюсь закрыть TCPClient, связанный со старым соединением. Когда я это делаю, новый TCPClient также умирает, и клиентская программа выдает эту ошибку:

E/mono    (12944): Unhandled Exception: System.IO.IOException: Write failure ---> System.Net.Sockets.SocketException: The socket has been shut down

И сервер выдает эту ошибку:

Unable to write data to the transport connection: An established connection was aborted by the software in your host machine.

Cannot read from a closed TextReader.

Итак, закрытие старого TCPClient с удаленной конечной точкой скажем: 192.168.1.10:50001

Также разрывает новый TCPClient с удаленной конечной точкой, скажем: 192.168.1.10:50002

Таким образом, два объекта TCPClient имеют одинаковый IP-адрес удаленной конечной точки, но разные порты удаленной конечной точки. Но закрытие одного, кажется, мешает другому работать. Я хочу иметь возможность закрыть старый TCPClient для выполнения моей очистки, не закрывая новый TCPClient.

Я подозреваю, что это как-то связано с тем, как TCPClient работает с сокетами на низком уровне, но у меня нет реального понимания этого, я не могу это исправить.

Ответы [ 3 ]

3 голосов
/ 08 февраля 2012

У меня была похожая проблема на моем сокет-сервере. Я использовал простой список вместо словаря для хранения всех моих текущих соединений. В непрерывном цикле while, который прослушивает новые потоки, у меня есть try / catch, и в блоке catch он убивает клиента, если он отключился.

Примерно так на sever.cs:

public static void CloseClient(SocketClient whichClient)
        {
            ClientList.Remove(whichClient);
            whichClient.Client.Close();
            // dispose of the client object
            whichClient.Dispose();
            whichClient = null;
        }

, а затем простой метод удаления на клиенте:

public void Dispose()
        {
            System.GC.SuppressFinalize(this);
        }

РЕДАКТИРОВАТЬ: эта вставка является разрешением OPs, которые он сам нашел с помощью моего кода.

Итак, чтобы уточнить, ситуация такова, что у меня есть два объекта TCPClient TCPClientA и TCPClientB с разными портами удаленных конечных точек, но с одним и тем же IP:

TCPClientA.Client.RemoteEndPoint.ToString();

возвращает: 192.168.1.10:50001

TCPClientB.Client.RemoteEndPoint.ToString();

возвращает: 192.168.1.10:50002

TCPClientA необходимо очистить, потому что он больше не нужен, поэтому я звоню

TCPClientA.Close();

Но это почему-то закрывает сокет для клиента на другом конце TCPClientB. Тем не менее, написание

TCPClientA.Client.Close();
TCPClientA.Close();

Успешно закрывает TCPClientA, не мешая TCPClientB. Итак, я исправил проблему, но я не понимаю, почему это так работает.

0 голосов
/ 10 февраля 2012

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

Отказ от ответственности: Это коммерческий продукт, и я являюсь его основателем.

0 голосов
/ 08 февраля 2012

Это звучит как ошибка в вашем коде. Закрытие одного входящего соединения не должно закрывать другое.

...