2014-01-03 11 views
3

Я написал службу Windows, которая выполняет функцию функции Modbus WriteMultipleRegisters через TCP, используя библиотеку NModbus для трехсторонних устройств каждые 10 минут (тики System.Threading.Timer).C# Modbus/tcp - висящее соединение

Иногда это соединение повесьте трубку, как правило, во время сетевых проблем. Поскольку устройство принимает только одно соединение Modbus вовремя, а другим отказано, соединение во время всех следующих тиков завершается с ошибкой SocketException - ConnectionRefused.

Но устройство автоматически закрывает соединения, которые не реагируют после короткого времени. Что-то должно держать связь открытой на моей стороне даже на два дня. Более того, когда моя служба перезагружается, все снова хорошо. Таким образом, есть определенно некоторая забытая открытая связь. Но мне не удалось воспроизвести эту ошибку в dev, поэтому я не знаю, где/когда ... соединение зависает. Я знаю только, что следующее соединение отказано.

Я делаю вызов функции MODBUS с этой частью коды:

using (TcpClient client = new TcpClient(device.ip, 502)) 
    { 
    using (Modbus.Device.ModbusIpMaster master = Modbus.Device.ModbusIpMaster.CreateIp(client)) 
      { 
      master.WriteMultipleRegisters(500, new ushort[] { 0xFF80 }); 
    } 
} 

device.ip является строкой, содержащей IP-адрес устройства - это правильно, подтверждено из деталей SocketException.

Поскольку я использую использование выражения, команда dispose вызывается для обоих объектов. Я посмотрел прочный NModbus исходный код, и все расположено правильно.

Любая идея, насколько возможно, что с этим подключением кода не закрыт?

+0

Вы _sure_, что '.Dispose' предполагается закрыть соединение? Я столкнулся с этой проблемой с другой сетевой библиотекой. Это может просто очистить ресурсы, не на самом деле «закрывая» что угодно. – nemec

+0

Да, я последовал за этим. Вызвать библиотеку вызовов и библиотеку TcpClient.Dispose. NModbus использует библиотеку unme для утилизации (файл: https://code.google.com/p/unme/source/browse/trunk/src/Unme.Common/DisposableUtility.cs) – Rfilip

+1

'Shutdown' и' Dispose' являются двумя очень различные методы. 'Shutdown' отправляет сообщение« мы закончили »на другой конец, в то время как' Dispose' не всегда гарантирует это.Кроме того, отдельно от любых проблем с C# не забывайте, что TCP-соединения фактически не закрыты до истечения времени ожидания (чтобы не допустить, чтобы данные, зависающие в интернет-инфраструктуре, доставлялись в недавно открытое соединение на том же порту). Очень важно обрабатывать изящное завершение работы, поскольку любые затяжные TCP-соединения могут занять 2-4 минуты, чтобы фактически закрыть очередь .NET finalizer ... – Luaan

ответ

3

Я согласен с nemec. Если вы просмотрите документацию для TcpClient.Dispose, если конкретно не упоминается закрытие соединения. Он освобождает управляемые и неуправляемые ресурсы по умолчанию, но может неправильно разорвать соединение.

Попробуйте изменить свой код:

using (TcpClient client = new TcpClient(device.ip, 502)) 
{ 
    try 
    { 
     using (Modbus.Device.ModbusIpMaster master = Modbus.Device.ModbusIpMaster.CreateIp(client)) 
     { 
      master.WriteMultipleRegisters(500, new ushort[] { 0xFF80 }); 
     } 
    } 
    catch(Exception e) 
    { 
     // Log exception 
    } 
    finally 
    { 
     client.Close(); 
    } 
} 

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

+0

Возможно, док не понял, но я посмотрел с использованием ILSpy (http://ilspy.net/) в исходный код System.Net.TcpClient, а Close - просто псевдоним для Dispose, потому что рядом с журналом вызывается только Dispose. Тогда только в Dispose все, включая Socket и NetworkStream, удалено/выпущено/закрыто ... – Rfilip

+2

Согласно документам, это не просто псевдоним. «Метод Close помещает экземпляр как расположенный и запрашивает, что связанный Socket закрывает TCP-соединение. Основываясь на свойстве LingerState, TCP-соединение может оставаться открытым в течение некоторого времени после вызова метода Close, когда данные еще не отправлены. уведомление об отсутствии, когда базовое соединение завершило закрытие. Вызов этого метода в конечном итоге приведет к закрытию связанного сокета и также закроет связанный с ним NetworkStream, который используется для отправки и приема данных, если он был создан ». – ZaXa

+0

Используете ли вы ту же среду выполнения .NET в развернутой версии, что и версия для разработки? Вы упомянули, что не видели этого в развитии. – ZaXa

1

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

 try 
     { 
      try 
      { 
       try 
       { 
        // Close the stream 
        var stream = _tcpClient.GetStream(); 
        if (stream != null) 
         stream.Close(); 
       } 
       catch { } 

       try 
       { 
        // Close the socket 
        if (_tcpClient.Client != null) 
         _tcpClient.Client.Close(); 
       } 
       catch { } 

       // Close the client 
       _tcpClient.Close(); 
       _tcpClient = null; 
      } 
      catch { } 

      if (_device != null) 
      { 
       _device.Dispose(); 
       _device = null; 
      } 
     } 
     catch { } 

     System.Threading.Thread.Sleep(1000); 
Смежные вопросы