Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.65/40: Рейтинг темы: голосов - 40, средняя оценка - 4.65
0 / 0 / 0
Регистрация: 03.09.2015
Сообщений: 30

Как определить, что TCP сессия была закрыта на другом конце

27.11.2015, 11:18. Показов 7776. Ответов 22
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Пишу реализацию сетевого протокола, который работает поверх TCP/IP. Протокол работает по принципу клиент-сервер. Клиент начинает TCP сессию, внутри сессии отправляет запрос, сервер только шлет ответ на запрос. Пар запрос-ответ внутри сессии может быть сколько угодно, сессия по продолжительности не ограничена и завершается на стороне клиента. Сервер многопоточный, поддерживает несколько сессий.
Пишу серверную часть, вопросы по ней. Стартую TcpListener и жду соединения методом Listener.AcceptTcpClient() .
Когда приходит входящее соединение, то от TcpListener получаю TcpClient и вызываю в новом потоке свой метод Session. В этом методе происходит весь диалог между сервером и клиентом. После закрытия TCP сессии нужно выйти из метода Session и завершить поток.
Все сделано на основе статей по простейшим серверам и по примерам из MSDN.
Вот сам метод в котором идет общение внутри сессии (как пример, часть кода вырезано):
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
       void Sesion(object clientObj)
        {
            // начало потока для TCP сессии
 
            TcpClient client = (TcpClient)clientObj;
            NetworkStream stream = client.GetStream();
 
            Debug.WriteLine("Начадо сессии с IP " + IPAddress.Parse(((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString()));
 
            while (client.Connected == true) // !!! Как определить, что сессия закрылась на стороне клиента?
            {
                if (client.Available > 0) // что-нибудь пришло?
                {
 
                    // читаем запрос
                    stream.Read(requestBuffer, 0, requestLenght);
 
                    // формируем ответ и отправляем
                    stream.Write(responseBuffer, 0, responseLenght);
                }
                else { Thread.Sleep(10); } // ждем данных
            }
 
            // Сюда должны попадать после закрытия сессии,
            // но никогда не попадаем.
 
            Debug.WriteLine("Завершение сессии"); 
            stream.Close();
 
            // завершение потока
        }
Проблема: нужен критерий, чтобы определить закрытие TCP сессии клиентом. Сейчас сделано
C#
1
 while (client.Connected == true)
Но если клиент закрыл сессию, то client.Connected не становится false. Насколько понял, чтобы это свойство перешло в false после отключения клиента, дополнительно нужно отправить данные и не получить подтверждения от клиента. Но в моем случае сервер отправляет какие-либо данные только по запросу клиента. Сервер не может сам отправить данные для проверки сессии, т.к. это нарушит логику работы протокола. Мне нужен способ отправлять служебные TCP пакеты без данных или найти другой критерий проверки сессии.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
27.11.2015, 11:18
Ответы с готовыми решениями:

Определить - была ли закрыта форма
Сегодня заметил такой ньюанс, если ресурсы формы были освобождены Close, она все равно ещё как призрак остается в роли объекта, даже...

Как определить, что форма открыта или закрыта
Здравствуйте. У меня в проекте несколько форм. Из главной формы я могу открывать другие формы: Form2.Show(), Form3.Show(). И закрывать:...

Как узнать, каким образом была закрыта форма?
Здравствуйте. Подскажите как узнать каким образом была закрыта форма. ( Form_Close() ) под действием пользователя, который нажал...

22
 Аватар для fufel
20 / 20 / 6
Регистрация: 28.02.2011
Сообщений: 535
10.11.2016, 12:14
Студворк — интернет-сервис помощи студентам
Добрый день, извините что задержался с ответом. Сидел и писал свою реализацию, и теперь на ваш суд выношу словесную реализацию решение своей задачи. Может где то я допустил тотальную ошибку которая мне аукнутся пос же.

На стороне клиента:
Что использую: TCPClietn + NetworkStream
Создаю два потока, первый поток принимает входящие сообщения, второй поток каждый 2 секунда шлёт "$$KeepAlive$$$" сообщение.

На стороне сервера:
Что использую: TCPClietn + NetworkStream
На каждое соединение я также создаю свой поток но при инициализации NetworkStream я делаю так ReadTimeout = 6000; (6 секунд).
Благодаря этому сам NetworkStream следит за тем что время ожидание "$$KeepAlive$$$" сигнала не превышало 6 секунд. Промежуток между сообщениями привысило больше 6 секунд то NetworkStream вызывает Exception и соединение закрывается.

Ещё один маленький вопрос, а может зря я начал писать свой протокол тогда когда уже есть что то готовое?

буду рад любым комментариям.
0
484 / 397 / 68
Регистрация: 14.02.2014
Сообщений: 1,930
10.11.2016, 13:11
Цитата Сообщение от fufel Посмотреть сообщение
второй поток каждый 2 секунда шлёт "$$KeepAlive$$$" сообщение.
не надо слать каждые 2 секунды. Сделай хотя-бы минуту. Да и слать надо не просто так, а только если нет рабочего обмена.

Цитата Сообщение от fufel Посмотреть сообщение
использую: TCPClietn + NetworkStream
Используй стандартные методы сокетов BeginSend, BeginReceive и т.д. Не строй велосипеды.

Цитата Сообщение от fufel Посмотреть сообщение
при инициализации NetworkStream я делаю так ReadTimeout = 6000;
Во-первых, не надо так делать.
Во-вторых, интервал очень маленький. Например, если данные передаются по каналам мобильной связи типа GPRS, то там пакет может "гулять" до полутора минут.

Цитата Сообщение от fufel Посмотреть сообщение
Ещё один маленький вопрос, а может зря я начал писать свой протокол тогда когда уже есть что то готовое?
Конечно есть. Открытых протоколов обмена "просто завались" ©. Вот только:
1) Они либо заточены под конкретные задачи, либо универсальны, из-за чего слишком громоздки (например, протокол по ГОСТ Р МЭК 61107)
2) Могут быть рассчитаны на быстрое проводное подключение с гарантированной доставкой (например, Modbus)

Если задача узко-специализирована есть смысл написать свой протокол (при учёте, что он небольшой). Или вообще прислушаться к тов. insite2012 и реализовать обмен через WCF (при условии, что у тебя обмен идёт между приложениями).
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
10.11.2016, 13:24
Цитата Сообщение от fufel Посмотреть сообщение
на ваш суд выношу словесную реализацию решение своей задачи.
Я бы сделал без дополнительных потоков, а с обычным таймаутом и двумя сообщениями: проверка состояния и ответ.
Если приходит сообщение $$KeepAlive$$$, то посылается ответ "$$OK$$".
На обеих сторонах устанавливается таймаут на принятие сообщения. Если произошел таймаут, то посылается сообщение "$$KeepAlive$$$". Если соединение было в полуоткрытом состоянии, то на этом шаге вылетит SocketException. Если после отправки сообщения снова произошел таймаут при приеме, то другая сторона по какой-то причине не отвечает — тут смотрите сами что делать: слушать дальше или попробовать пересоединиться.

При таком подходе у вас отпадает необходимость в отдельных потоках и если сообщения будут идти регулярно, то не придется слать keep-alive пакеты.

Цитата Сообщение от fufel Посмотреть сообщение
уже есть что то готовое?
В самом протоколе TCP есть поддержка Keep-Alive, но она не самая надежная, т.к. некоторые роутеры этот пакет тупо игнорируют.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
10.11.2016, 13:24

Как в VS откатить файлы кода, если ранее они были уже сохранены и VS была закрыта?
Как в VS откатить файлы кода, если ранее после изменений они были уже сохранены и VS была закрыта?

Отмена действия, если форма была закрыта через крестик
Как сделать, чтобы если закрыли Form2 через крестик, не выполнялась процедура DrawPS ? begin Form2.ShowModal; DrawPS(X, Y,...

Как определить, что была нажата кнопка (крестик) закрытия формы
Как определить что была нажата кнопка закрытия формы непосредственно в событии FormClosing/FormClosed? Сейчас использую такой код, но...

Как указать что форма закрыта, после её открытия и вызова программно
Привет. Я хотел бы просто спросить у вас как указать что вторая форма закрыта, после её открытия и вызова программно. Форма 2 закрывается...

Как узнать какой ip-адрес на другом конце кабеля
здравствуйте!!! есть такой вопрос. вообщем стоит хаб в нем кабеля не подписанные, вот сам вопрос можно ли стоя у хаба вынимая провода по...


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

Или воспользуйтесь поиском по форуму:
23
Ответ Создать тему
Новые блоги и статьи
Саморегулирующийся социальный контракт для сервера cross-section.
Hrethgir 14.08.2026
С кодом конечно таких глубоких размышлений пока не было, впрочем я уже привык к алгоритмизации. Суть предмета записи: снова в диалоге с нейросетью (я взял пока себе ник для учётки админа - Rector). . . .
Часы электронные
Uhbif79 12.08.2026
Выкладываю программу часов. Программа позволяет: 1. Использовать системное время и дату, 2. Есть возможность вводить время и дату вручную. 3. Реализованы 2 будильника: начало и конец рабочего дня. . . .
Часы с будильником на основе класса QLCDNumber
Uhbif79 12.08.2026
Всем добрый день, выкладываю программу часов с будильником на основе класса QLCDNumber. Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
Установка MinGW GCC 16.2 и CMake
8Observer8 10.08.2026
VK Видео: https:/ / vkvideo. ru/ video-240781534_456239017 YouTube: eY5-5PyI9NM Текстовая версия
Неделя из жизни имитационной модели склада: мои кривые руки растут, откуда надо
anaschu 10.08.2026
Неделя из жизни имитационной модели склада: как я почти написал неправильную логику и что с этим делать Работаю сейчас над учебно-рабочим проектом: строю в AnyLogic имитационную модель процессов. . .
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru