Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Любопытное поведение System.Net.Sockets

241
30 января 2008 года
Sanila_san
1.6K / / 07.06.2005
Преамбула.

Имеется поток, в котором выполняется примерно такая функция:
Код:
[COLOR="Blue"]  Public Sub[/COLOR] SMPPWorkCycle([COLOR="Blue"]ByVal[/COLOR] data [COLOR="Blue"]As Object[/COLOR])
        [COLOR="Blue"]Dim[/COLOR] netmod [COLOR="Blue"]As New[/COLOR] NetworkModule [COLOR="Green"]'Это узкозаточенная оболочка над классом System.Net.Sockets.Socket[/COLOR]
        [COLOR="Blue"]Try[/COLOR]
            [COLOR="Blue"]While [/COLOR](m_state = ServiceState.Started)

                netmod.Connect(ipaddr, port)
                [COLOR="Blue"]While [/COLOR]m_state = ServiceState.Started [COLOR="Blue"]And [/COLOR]netmod.Connected
                    DoSomething(netmod) [COLOR="Green"]'Тут мы в цикле обращаемся к БД и по сети шлём данные.[/COLOR]
                [COLOR="Blue"]End While[/COLOR]
                [COLOR="Blue"]If[/COLOR] netmod.Connected = False Then
                    [COLOR="Blue"]Try[/COLOR]
                        netmod.Disconnect()
                    [COLOR="Blue"]Catch[/COLOR] ex [COLOR="Blue"]As[/COLOR] Exception
                        [COLOR="Green"]'Обрабатываем исключение[/COLOR]
                    [COLOR="Blue"]End Try
                End If
            End While
        Catch[/COLOR] ex [COLOR="Blue"]As[/COLOR] Exception
                        [COLOR="Green"]'Обрабатываем исключение[/COLOR]
        [COLOR="Blue"]End Try
    End Sub[/COLOR]
Используется протокол SMPP, особенность его в том, что подразумевается проверка связи на прикладном уровне, делается это специальной командой, которую одна из сторон шлёт с некоторым интервалом. В моём случае это 10 минут. Сокеты для простоты используются блокирующие, после отправки сокет переключается в режим прослушивания и ждёт входящие данные 12 минут, если данных нет, то происходит дисконнект. Поскольку при этом
 
Код:
m_state = ServiceState.Started
, то происходит попытка повторного подключения сокета к удалённому хосту.

Амбула.
Гадость ситуации в том, что иногда процедура DoSomething не знает о том, что сокет отключился, поэтому подвешивает сервер обращениями к БД. В самой процедуре DoSomething имеется цикл по условию
 
Код:
[COLOR="Blue"]While [/COLOR](netmod.Connected = [COLOR="Blue"]True[/COLOR])
, в этом цикле происходит вся работа процедуры, стало быть, если сокет отключен, цикл не должен запускаться.

Отсюда вопросы:
  1. Насколько быстро свойство socket.Connected меняет своё состояние? Есть подозрение, что сразу, но тогда возникает второй вопрос:
  2. Почему при попытке послать данные в отключенный сокет не всегда возникает исключение с выходом из функции?
8.9K
14 февраля 2008 года
Pulf
13 / / 15.01.2005
На собственном опыте сталкивался с такой проблемой. Свойство Connected порой выдает желаемое за действительное (подключения по сокету нет, а оно уверяет, что все в порядке), но в таком случае при посылке (Send), вываливается исключение (это собственно и означает, что с подключением беда). После этого "передергиваем" сокет (например, тупо создаем новый объект сокета) и все работа возобновляется.
Чтобы не быть голословным, вот ссылки по теме: http://msdn.microsoft.com/library/rus/default.asp?url=/library/RUS/cpref/html/frlrfSystemNetSocketsSocketPropertiesTopic.asp и http://msdn2.microsoft.com/en-us/library/system.net.sockets.socket.connected(VS.71).aspx
241
15 февраля 2008 года
Sanila_san
1.6K / / 07.06.2005
Спасибо. :) Мы тоже это заметили. Единственное, что помогает, это отлов исключений, они, к счастью, возникают исправно.
241
21 февраля 2008 года
Sanila_san
1.6K / / 07.06.2005
Я смотрю, тема сохраняет популярность. Поэтому подведу итог изучения вопроса.
  • Свойство Connected обновляется в момент проведения последней операции на сокете. Это значит, что если мы успешно отправили данные, а удалённый хост в через какое-то время взял и отвалился, свойство Connected об этом ничего знать не будет, поэтому при попытке повторной отправки данных возникнет исключение. Это не баг, это фича от MS, причём, как ни парадоксально звучит, фича довольно логичная.
  • Хочу предостеречь от одной своей ошибки: если отправка данных не удалась, не стоит вызывать метод сокета Disconnect(), поскольку в этом случае возникнет исключение (ельзя разорвать уже разорванное соединение), которое вы забудете обработать. В этом случае оно непременно повесит функцию более верхнего уровня.
  • Проверить наличие связи в данный момент по значению свойства Connected невозможно, оно лишь показывает, что связь была во время последней операции, и предполагается, что она есть и сейчас, хотя на самом деле это не обязательно так. Отсюда вывод: надо всегда работать с сокетами в блоке Try...Catch, либо обрабатывать исключения в функции верхнего уровня.
  • Из вышесказанного следует: проверьте, не потеряете ли вы данные при обработке исключения, предусмотрите механизм повторной отправки данных.
  • Характерно, что при разрыве связи по нашей инициативе свойство Connected принимает значение False, а при разрыве по инициативе удалённого хоста оно не принимает нового значения, поэтому при отправке данных возникнет исключение, а при приёме по истечению таймаута сокет вернёт ноль байт, что тоже следует рассматривать как разрыв соединения и соответственно обрабатывать.
Вышесказанное отражает мой личный опыт использования класса System.Net.Sockets.Socket, и исчерпывающе объясняется первоисточником (см. ссылки от Pulf). Если у кого-то есть ещё мысли по этому поводу, буду очень рад с ними познакомиться.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог