С Новым годом! Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.84/57: Рейтинг темы: голосов - 57, средняя оценка - 4.84
1 / 1 / 0
Регистрация: 20.05.2011
Сообщений: 17
1

Узнать, что отключился TcpClient

16.08.2012, 15:09. Показов 10946. Ответов 20
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Добрый день. Прекрасно понимаю, что реализаций всяческих многопоточных серверов тонны в интернете. Каждый делает их по-своему, нет никакого четкого стандарта (и быдлокодерства гораздо больше, чем толковых статей). Никто из пишущих примеры, похоже, и вовсе не понимает, что пакеты могут быть склеены, разорваны и так далее.
В общем, полазив везде и всюду, написал простенький коннектор для одного клиента (мне больше не надо). Но, черт, невозможно узнать, что TcpClient отключился. Вот вообще. Свойство TcpClient#Connected все время показывает true.
Варианты с отсылкой какого-то сообщения перед закрытием коннекта с клиента посылать я не могу, ибо мне нужно учесть ситуацию, когда клиент аварийно завершил работу (да свет вырубили)

Помогите, пожалуйста, как же узнать, что нужно выйти из цикла?
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void acceptCallback(IAsyncResult result) {
    _client = _socket.EndAcceptTcpClient(result);
    _netStream = _client.GetStream();
 
    // принятие данных
    while (_client.Connected) {
        int bytesAvailable = _client.Available;
        
        // если сокет не молчит
        if (bytesAvailable != 0) {
            recieveData(bytesAvailable);
        }
    }
}
В recieveData отправляю буфер на декодирование, вычленение пакетов. Да, протокол у меня бинарный, не UTF-строки.

Добавлено через 1 час 38 минут
http://msdn.microsoft.com/ru-r... ected.aspx
Вот что есть. И написано так здорово. Эдакий пустой пинг на проверку соединения. Но даже он не работает.
Набыдлокодил вот так:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
_socketClient = _client.Client;
 
while (_socketClient.Connected) {
    // попингуй
    bool blockingState = _socketClient.Blocking;
    try {
        _socketClient.Blocking = false;
        _socketClient.Send(new byte[1], 0, 0);
    }
    catch (SocketException ex) {
            // 10035 == WSAEWOULDBLOCK
            if (ex.NativeErrorCode.Equals(10035)) {
                        
            }
            else {
                break;
            }
    }
    finally {
        _socketClient.Blocking = blockingState;
    }
...
Прямо из примера и взял код. Но в чем дело, в этом случае Connected тоже всегда true. Но стоит дебаггером влезть в содержимое сокета, чтобы посмотреть значения свойств, как это свойство сразу же становится False и из цикла выходит нормально. А если не лезть дебаггером, так все True и будет.
Что за бред?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
16.08.2012, 15:09
Ответы с готовыми решениями:

Как узнать что удаленный клиент отключился
Здравствуйте. При подключение клиента создается список клиентов NetworkStream networkStream =...

Клиент-сервер: Как определить, что клиент отключился?
Привет. Есть клиент и сервер, при подключении клиента, на сервере создается класс, который содержит...

TcpClient. Как понять на сервере что клиент отключился?
как понять на сервере что клиент отключился?

Как узнать, что неблокирующий сокет отключился
Здравствуйте, нужен неблокирующий клиентский сокет, который работает до тех пор, пока соединение...

20
47 / 47 / 9
Регистрация: 13.02.2012
Сообщений: 176
16.08.2012, 15:20 2
Цитата Сообщение от kordum Посмотреть сообщение
Никто из пишущих примеры, похоже, и вовсе не понимает, что пакеты могут быть склеены, разорваны и так далее.
Ты работаешь с сокетами по протоколу TCP. Особеннось данного протокола, что именно он берет на себя ответственность за целостность передачи данных. Т.е. если ты передаешь по TCP можешь быть абсолютно уверен, что пакет 5 не придет клиенту раньше пакета 4, или что пакет 4 придет битый.
После передачи данных сокет не знает когда ему остановиться слушать. И ждет еще. Попробуй кинуть
C#
1
Socket.Shutdown(SocketShutdown.Send);
После передачи с одной стороны, в вторая тут же перестанет принимать.
Кидай сразу кусок твоего Soсket сервера к клиенту, и разберемся что не так.
0
1 / 1 / 0
Регистрация: 20.05.2011
Сообщений: 17
16.08.2012, 15:28  [ТС] 3
Ты работаешь с сокетами по протоколу TCP. Особеннось данного протокола, что именно он берет на себя ответственность за целостность передачи данных.
Да, но два мелких пакета могут быть склеены. А большой пакет может придти в нескольких пачках (MTU же). Поэтому я перед сообщением 4 байтами вшиваю длину сообщения. Но не суть.

Кидай сразу кусок твоего Soсket сервера к клиенту, и разберемся что не так.
Не понял просьбы. У меня ведь именно проблема с определением отваливания клиента от сервера. Сам клиент написан на AS3.

Вот весь код работы с сокетом клиента:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private void acceptCallback(IAsyncResult result) {
    _client /* TcpClient */ = _socket.EndAcceptTcpClient(result);
    _socketClient /* Socket */ = _client.Client;
    
    // принятие данных
    while (_socketClient.Connected) {
        // попингуй
        bool blockingState = _socketClient.Blocking;
        try {
            _socketClient.Blocking = false;
            _socketClient.Send(new byte[1], 0, 0);
        }
        catch (SocketException ex) {
            // 10035 == WSAEWOULDBLOCK
            if (ex.NativeErrorCode.Equals(10035)) {
                
            }
            else {
                break;
            }
        }
        finally {
                _socketClient.Blocking = blockingState;
        }
        
        int bytesAvailable = _client.Available;
        
        // если сокет не молчит, то отправляем пришедшие байты на разбор
        if (bytesAvailable != 0) {
            recieveData(bytesAvailable);
        }
    }
}
Лишнее я, конечно же, убрал, что не относится к проблеме.
0
47 / 47 / 9
Регистрация: 13.02.2012
Сообщений: 176
16.08.2012, 21:54 4
Во первых. Еще раз, то что они могут быть склеены, расклеены и т.д. вообще не твоя забота. И MTU тут не причем. Ты читаешь байты из сокета как из обычного stream.
Во вторых, сейчас только внимательно глянул кусок твоего кода.
C#
1
private void acceptCallback(IAsyncResult result)
Это я так понимаю, метод который ты подсовываешь в BeginAccept, тут вроде все правильно, но
C#
1
while (_socketClient.Connected) {
где ты это условие увидел? Покажи хоть один пример с msdn? Я вообще не понимаю что ты таким циклом хочешь сделать. После принятия соединения, если ты например хочешь отправлять, то метод должен выглядеть примерно так
C#
1
2
3
4
5
6
7
        static void ClientAccepted(IAsyncResult e)
        {
            Socket listener = e.AsyncState as Socket;
            Socket handler = listener.EndAccept(e);
            byte[] message = new byte[100];
            handler.BeginSend(message, 0, message.Length, 0, new AsyncCallback(SendComplited), handler);
        }
Я думаю стоит еще раз внимательно посмотреть на msdn
1
1 / 1 / 0
Регистрация: 20.05.2011
Сообщений: 17
17.08.2012, 00:57  [ТС] 5
Во первых. Еще раз, то что они могут быть склеены, расклеены и т.д. вообще не твоя забота.
Как это не моя, если я потом из общей кучи байтов должен сообщения выгребать, которые сформированы по моему протоколу? То, что там в буфер валится, мне без разницы до того момента, пока я не отошлю буфер на декодирование. В конкретном куске кода мне без разницы, склеены пакеты или нет. Мне необходимо принять все байты, что валятся в сокет от клиента, что я и делаю.
Я перерыл кучу статей, там нигде не берут во внимание при декодировании, что пакеты могут быть склеены - вот я к чему.
Подозреваю, что Вы мою фразу про склейку приняли не за "оффтопик", а за относящееся к проблеме.

Это я так понимаю, метод который ты подсовываешь в BeginAccept
Подсовываю, угу.
где ты это условие увидел?
Это условие написал после прочтения ссылки.
Значение свойства Connected отражает состояние подключения в результате последней операции. Если необходимо определить текущее состояние подключения, выполните неблокирующий вызов Send с нулевым числом байтов. Успешное выполнение запроса или создание исключения с кодом ошибки WAEWOULDBLOCK (10035) указывает на то, что сокет по-прежнему подключен; в противном случае, сокет уже не подключен.
И сделал логичные умозаключения, что нужно пускать бесконечный цикл принятия байт по сокету, опираясь на это свойство.

если ты например хочешь отправлять
Мне нужно получать. Отправку я еще не делал. Шаблон заготовлен для записи пакета в сокет, но парюсь пока только с принятием и контролем коннекта. К слову, с моим кодом все принимается хорошо. Что смущает в алгоритме?

Добавлено через 2 минуты
А вот ссылку Вы привели классную. То, что нужно, на событиях-коллбэках. Без этого дебильного большого while на все про все.

Добавлено через 3 минуты
А. Все здорово, кроме одной вещи. Почему буфер, в которой считывается, всегда фиксированной длины?
C#
1
byte[] bytes = new Byte[1024];
Можно ли как-то создать его так, чтобы он был равен точно значению свойства Available?
Мне ведь потом отправлять на декодирование его. А оно как раз подразумевает, что все доступные байты уместились в буфере и пустых байтов там нет.

Добавлено через 10 минут
Так как все-таки проверять, что клиент отвалился на том конце сокета?

Добавлено через 2 часа 23 минуты
Можно ли как-то создать его так, чтобы он был равен точно значению свойства Available?
Мне ведь потом отправлять на декодирование его. А оно как раз подразумевает, что все доступные байты уместились в буфере и пустых байтов там нет.
Уже не актуально.
Так как все-таки проверять, что клиент отвалился на том конце сокета?
До сих пор актуально. Переделал сокет на асинронный по примеру на MSDN

Добавлено через 11 минут
О! Кажется дошло. Вот так нужно определять?
C#
1
2
3
4
5
6
7
8
9
10
private void readCallback(IAsyncResult ar) {
    int bytesAvailable = _client.EndReceive(ar);
 
    if (bytesAvailable > 0) {
        // отправляем на декодирование
    }
    else {
        // отвалился клиент
    }
}
0
146 / 143 / 32
Регистрация: 21.01.2012
Сообщений: 545
20.08.2012, 12:47 6
когда клиент отключается, он посылает серверу сообщение длины 0
1
1 / 1 / 0
Регистрация: 20.05.2011
Сообщений: 17
20.08.2012, 13:02  [ТС] 7
Цитата Сообщение от KeBJIaP Посмотреть сообщение
когда клиент отключается, он посылает серверу сообщение длины 0
А если клиент вылетел пробкой и ничего не успел послать? Вот свет отрубили, а ИБП нет, чтобы корректно все завершиться успелось. Или например интернет в роутере помер. Как быть в такой ситуации?
0
352 / 331 / 49
Регистрация: 12.12.2011
Сообщений: 563
20.08.2012, 21:53 8
kordum, перефразирую
Когда клиент отлетает, сервер получает пакет длинной 0 байт
1
1 / 1 / 0
Регистрация: 20.05.2011
Сообщений: 17
20.08.2012, 21:55  [ТС] 9
Yukikaze, всегда-всегда, при любом казусе?
Спасибо, это-то я и хотел узнать. А то товарищи программеры напугали, что никак не узнать, если клиент серверу перед самым дисконнектом "превед" не сказал. Вот и одолевали сомнения.
0
22 / 21 / 8
Регистрация: 17.02.2011
Сообщений: 389
18.07.2024, 08:29 10
При закрытии формы клиента, сервер остаётся в режиме connected, ни каких сообщений 0 длины он не получает. Для чтения из потока использую Read. Пишут, что единственный способ это отправить какой-то тестовый пакет и что-то получить в ответ, другого способа нет.
0
Эксперт .NET
6511 / 4087 / 1606
Регистрация: 09.05.2015
Сообщений: 9,553
18.07.2024, 10:05 11
Если клиент отвалится аварийно, то любые попытки получить от него что-то или отправить ему что-то должны выбрасывать исключение, которое и следует обработать.
0
22 / 21 / 8
Регистрация: 17.02.2011
Сообщений: 389
18.07.2024, 11:54 12
Я сделал на серваке таймер, и по таймеру отправляю клиенту префикс, на стороне клиента если вижу префикс, отправляю обратно, ни куда не вывожу, отбрасываю. Закрываю клиента и тишина. Таймер продолжает слать данные, точка срабатывает, но для сервака ни один try catch не срабатывает. Я конечно мог бы просто посчитать количество успешных приёмов, но непонятно, должно ли вообще что-то происходить. Кстати, кое что начинает происходить если сделать вывод всех входящих сообщений, в том числе префикса, тогда выскакивает необрабатываемое исключение про дескриптор окна, не понятно откуда, ну и далее выход из потока чтения.

Добавлено через 11 минут
В связи с этим вопрос, разве tcp ip не обеспечивает сигналами о неудачной передачи, или просто делает это несколько раз?

Добавлено через 1 минуту
И что это за необратываемое исключение про дескриптор окна?
0
Эксперт .NET
17793 / 12944 / 3381
Регистрация: 17.09.2011
Сообщений: 21,226
18.07.2024, 13:20 13
Цитата Сообщение от leonidSDF Посмотреть сообщение
Кстати, кое что начинает происходить если сделать вывод всех входящих сообщений, в том числе префикса, тогда выскакивает необрабатываемое исключение про дескриптор окна, не понятно откуда, ну и далее выход из потока чтения
Посмотрите, не продолжает ли висеть процесс в диспетчере задач после закрытия окна.
Подозреваю, что где-то в коде вы запускаете отдельный поток для всего этого дела в режиме foreground, который не схлапывается автоматом.
Т.е. проблема скорее всего не в TCP, а в том, что вы только думаете, что клиент отключился, а на самом деле он продолжает принимать данные.
0
22 / 21 / 8
Регистрация: 17.02.2011
Сообщений: 389
19.07.2024, 05:13 14
Похоже, что вы правы, в диспетчере я ни чего не увидел, но если запустить клиент в режиме отладки и остановить её то сервак отрубается, не требуется даже делать посылки по таймеру. Будем смотреть, как закрываются потоки
0
Эксперт .NET
1989 / 1448 / 339
Регистрация: 15.06.2012
Сообщений: 5,438
Записей в блоге: 3
19.07.2024, 10:18 15
Цитата Сообщение от kordum Посмотреть сообщение
C#
1
2
while (_client.Connected) {
        int bytesAvailable = _client.Available;
Available вообще кажись про наличие данных в буфере, что из другой оперы.

Я в 99% случаев завязываюсь на то что Read при закрытии вернет 0. Что делать когда удаленная сторона закрывает поток только на чтение, но не на запись -- не в курсе.
0
1150 / 858 / 263
Регистрация: 30.04.2009
Сообщений: 3,598
20.07.2024, 20:33 16
В самом протоколе TCP нет втроенной функции определения что клиент отвалился. Как workaround используют пинг-понг пакеты. Если вторая сторона не отвечает, значит соединение прервано.
0
Эксперт .NET
1989 / 1448 / 339
Регистрация: 15.06.2012
Сообщений: 5,438
Записей в блоге: 3
21.07.2024, 16:49 17
Цитата Сообщение от nicolas2008 Посмотреть сообщение
В самом протоколе TCP нет втроенной функции определения что клиент отвалился
Зависит от реализации протокола (внезапно). На винде и линуксе вроде это есть. В этом случаю сам протокол шлет ping-pong пакеты, и мониторит нештатные разрывы. Как чекнуть его наличие не нашел, но очень много инфы про то как настроить, например устаревший вариант https://learn.microsoft.com/en... ew=net-8.0
1
1150 / 858 / 263
Регистрация: 30.04.2009
Сообщений: 3,598
23.07.2024, 02:24 18
Wolfdp, keep alive это не то
0
Эксперт .NET
1989 / 1448 / 339
Регистрация: 15.06.2012
Сообщений: 5,438
Записей в блоге: 3
23.07.2024, 17:44 19
Цитата Сообщение от nicolas2008 Посмотреть сообщение
Wolfdp, keep alive это не то
WAT?
https://en.wikipedia.org/wiki/Keepalive

Each host (or peer) periodically sends a TCP packet to its peer which solicits a response. If a certain number of keepalives are sent and no response (ACK) is received, the sending host will terminate the connection from its end.
Добавлено через 12 минут

Не по теме:

p.s. ужс... только сейчас заметил что оригинальная тема от 2012.

0
3684 / 2595 / 719
Регистрация: 02.08.2011
Сообщений: 6,968
23.07.2024, 18:33 20
Цитата Сообщение от Wolfdp Посмотреть сообщение
WAT?
Wolfdp, да не работает keep-alive, узнать об отключении стороны можно только попытавшись прочитать из подключениния - Socket.Receive.
Именно поэтому идея про ping-pong самая правильная.

Добавлено через 1 минуту
Вот вам актуальная инфа.
0
23.07.2024, 18:33
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
23.07.2024, 18:33
Помогаю со студенческими работами здесь

QTcpSocket узнать какой именно клиент отключился
У меня есть 2 программы на клиент-серверной связке Мне важно на сервера знать IP клиентов и их...

Как узнать, что картинка полностью загружена, чтобы узнать её размеры
Здраствуйте ! Делаю галерею. Мне нужно узнать когда картинка загрузица полносттю, чтобы узнать её...

Как узнать, что в ком порт что-то записалось?
Народ, подскажите как узнать что в ком порт что-то записалось, точнее пришло от подключенного...

отключился инет!!!
вопрос может показаться глупым но надеюсь на понимание!!!! с утра инет был и все работало! кабель...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Что такое CQRS и как это реализовать на C# с MediatR
InfoMaster 15.01.2025
Концепция CQRS и её роль в современной разработке В современном мире разработки программного обеспечения архитектурные паттерны играют ключевую роль в создании масштабируемых и поддерживаемых. . .
Как настроить CI/CD с Azure DevOps
InfoMaster 15.01.2025
CI/ CD, или непрерывная интеграция и непрерывное развертывание, представляет собой современный подход к разработке программного обеспечения, который позволяет автоматизировать и оптимизировать процесс. . .
Как настроить CI/CD с помощью Jenkins
InfoMaster 15.01.2025
Введение в CI/ CD и Jenkins В современной разработке программного обеспечения непрерывная интеграция (CI) и непрерывная доставка (CD) стали неотъемлемыми элементами процесса создания качественных. . .
Как написать микросервис на Go/Golang с Kafka и GitHub CI/CD
InfoMaster 14.01.2025
Определение микросервиса, преимущества использования Go/ Golang Микросервис – это архитектурный подход к разработке программного обеспечения, при котором приложение состоит из небольших, независимо. . .
Как написать микросервис с нуля на C# с RabbitMQ, CQRS и CI/CD
InfoMaster 14.01.2025
В современном мире разработки программного обеспечения микросервисная архитектура стала стандартом де-факто для создания масштабируемых и гибких приложений. Этот архитектурный подход предполагает. . .
Как создать интернет-магазин на PHP и JavaScript
InfoMaster 14.01.2025
В современном мире электронная коммерция стала неотъемлемой частью бизнеса. Создание собственного интернет-магазина открывает широкие возможности для предпринимателей, позволяя достичь большей. . .
Как написать Тетрис на Ассемблере
InfoMaster 14.01.2025
Тетрис – одна из самых узнаваемых и популярных компьютерных игр, созданная в 1984 году советским программистом Алексеем Пажитновым. За прошедшие десятилетия она завоевала симпатии миллионы людей по. . .
Как создать игру "Танчики" на Unity3d и C#
InfoMaster 14.01.2025
Разработка игр – это увлекательный процесс, сочетающий в себе творчество и технические навыки. В этой статье мы рассмотрим создание классической игры "Танчики" с использованием Unity3D и языка. . .
Организую платный онлайн микро-курс по доработке Android-клиента Telegram
_Ivana 14.01.2025
Официальная версия и распространенные форки не полностью устраивают? Сделай свою кастомную версию клиента! 4 занятия по 2 часа (2 недели пн, ср 19:00-21:00 по Москве). Первое вводное занятие. . .
Как создать приложение для фитнеса для iOS/iPhone на Kotlin
InfoMaster 14.01.2025
Создание собственного фитнес-приложения — это не только захватывающий, но и полезный процесс, ведь оно может стать вашим верным помощником на пути к здоровому и активному образу жизни. В современных. . .
Как создать приложение магазина для iOS/iPhone на Swift
InfoMaster 14.01.2025
Введение в разработку iOS-приложений Разработка приложений для iPhone и других устройств на базе iOS открывает огромные возможности для создания инновационных мобильных решений. В данной статье мы. . .
Это работает. Скорость асинхронной логики велика. Вопрос видимо останется в стабильности. Плата - огонь!
Hrethgir 13.01.2025
По прошлому проекту в Logisim Evolution https:/ / www. cyberforum. ru/ blogs/ 223907/ blog8781. html прилагаю файл архива проекта в Gowin Eda. Восьмибитный счётчик из сумматора+ генератор сигнала. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru