2013-08-22 4 views
9

Фон:
У меня есть код, который подключается к серверу для сбора данных. Однако в какой-то момент программа попала в состояние, когда он не смог подключиться к серверу. Проблема, которую мы наблюдаем, заключается в том, что сервер постоянно выходил из строя, когда мы пытались снова подключиться.Закрыть все сетевые подключения

Plugin:
У нас есть тайм-аут установлены значения по умолчанию, используемые нашей сети плагин (расчетливости плагин). Эти значения представляют собой тайм-аут 100 кбит/с и 300 кбит/с. Не совсем короткие таймауты. Кроме того, каждый раз, когда мы пытаемся повторно подключиться, мы воссоздаем класс плагина, поэтому любые значения, которые он устанавливает внутренне, сбрасываются каждый раз, когда мы пытаемся повторно подключиться. Я считаю, что тайм-ауты не являются проблемой. И я считаю, что плагин не проблема.

Сеть:
Мы видели, что эти повторяющиеся таймауты происходят в течение получаса. Когда мы перезапустили службу (а не машину), она сразу же вернулась в сеть. Итак, я знаю, что это не проблема сети. Это заставляет меня поверить, что в нашем коде есть что-то, что попадает в недопустимое состояние сети. Кроме того, это состояние, которое мы не можем контролировать, поскольку наш плагин скрывает от нас все хорошие сетевые материалы, включая таймауты, флаги keepalive и группы соединений (среди прочих). В основном у нас нет доступа к члену HTTPWebReqest.

Вопрос:
Когда наши настройки сети попадают в это состояние, мы пытаемся закрыть все соединения и повторного подключения к серверу. Цель состояла в том, чтобы убить все активные соединения, чтобы сбросить все состояние, в которое мы попали. Однако, когда мы пытаемся снова подключиться, мы получаем тайм-ауты на нашем повторном подключении.

Как-то (вероятно, из-за KeepAlive и TCP Конвейеризация, которые мы не можем контролировать), сетевые соединения остаются открытыми, даже если мы закрыли все соединения. Это оставляет нас в плохом состоянии и не позволяет нам подключаться к серверу.

Вопрос:
Как я могу убить все лежащее в основе подключение к серверу для того, чтобы вынудить переподключение?

+7

Лично я бы рекомендовал изменить библиотеку, которую вы используете. Однако, поскольку я - вы, я знаю, что это не вариант. – Richard

+0

+1. Хороший комментарий и ответ – Danexxtone

ответ

9

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

Кроме того, поскольку у вас есть , у вас нет доступа к keepalive (или HTTPWebRequest), вам нужно будет найти способ убить соединения вне параметров запроса.

Есть два подхода, которые можно предпринять, чтобы получить .Net, чтобы освободить эти соединения. Оба они включают переход на уровень ServicePoint и взаимодействие с группами соединений.

  1. CloseConnectionGroups

    При создании HTTPWebRequest, вы можете дать ему группы соединения. Оттуда вы можете использовать функцию CloseConnectionGroup() из ServicePoint, чтобы убить все подключения к этой службе.

    ServicePoint srvrPoint = ServicePointManager.FindServicePoint(serverUri); 
    srvrPoint.CloseConnectionGroup(myConnGroup) 
    

    Конечно, если у вас есть более чем одну группу соединений, вам необходимо сделать это в цикле для каждой группы соединений.

    Обратите внимание, что если вы выберете этот путь, будьте осторожны, чтобы не поместить все соединения в одну группу. Это может привести к выходу из сокетов. More information here.

  2. ReleaseAllConnectionGroups

    Существует внутренняя функция в классе ServicePoint, что вы можете назвать, что будет убивать все подключения к точке служите (т.е. сервер). Однако, поскольку это внутреннее к классу, вы должны будете использовать отражение, чтобы получить на него:

    ServicePoint srvrPoint = ServicePointManager.FindServicePoint(serverUri); 
        MethodInfo ReleaseConns = srvrPoint.GetType().GetMethod 
          ("ReleaseAllConnectionGroups", 
          BindingFlags.Instance | BindingFlags.NonPublic); 
        ReleaseConns.Invoke(srvrPoint, null); 
    

    Этот код просто вытаскивает ReleaseAllConnectionGroups из этого ServerPoint и вызывает его без параметров. Эта функция будет проходить через все группы соединений во внутреннем списке и освобождать все эти ресурсы - убивая все соединения.

    Downfall: Поскольку это частный член, вам не гарантируется, что он будет там, если вы обновите свою версию .Net. В настоящее время он доступен в версиях от версии 2.0 до 4.5. Ссылка на the reverse engineered code of ReleaseAllConnectionGroups.

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

К сожалению, нет никакого другого способа получить .Net, чтобы закрыть эти соединения низкого уровня и освободить их KeepAlive статус без установки флажка KeepAlive.

+1

Потратив много времени на устранение проблемы, я столкнулся с этим решением. Это работало как прелесть для меня. благодаря –

0

Почему бы не использовать ниже код:

SqlConnection.ClearAllPools();

Я использую его во всех своих приложениях.

Смежные вопросы