Can't set socket timeouts for MultiProtocolFrameParser


#1

I am trying to use the MultiProtocolFrameParser to read synchrophasor data for a custom program. I keep running into a problem where the device disconnects but the close packet never arrives because it’s on an unreliable network. This causes the MultiProtocolFrameParser to basically wait forever for packets that will never show up. From looking through the source code it looks like socket timeouts are never set anywhere and is probably what is causing this issue since their default setting is to wait forever.

Is there any way that I have missed to set timeouts or is there a workaround for this issue? I would prefer that the timeout fires so I can reconnect to the device.


#2

This wouldn’t be possible without a code change in GSF. The way we’ve traditionally solved this is using a timer to monitor the data stream, similar to the following. You may also want to attach to the ConnectionTerminated and ConnectionEstablished events so you can stop and start the monitoring timer during periods of time when the device is disconnected.

class DataStreamMonitor : IDisposable
{
    private MultiProtocolFrameParser m_frameParser;
    private System.Timers.Timer m_monitoringTimer;
    private long m_bytesReceived;
    private bool m_disposed;

    public DataStreamMonitor(MultiProtocolFrameParser frameParser)
    {
        m_frameParser = frameParser;
        m_frameParser.ReceivedFrameImage += m_frameParser_ReceivedFrameImage;

        // Create data stream monitoring timer
        m_monitoringTimer = new System.Timers.Timer();
        m_monitoringTimer.Elapsed += m_monitoringTimer_Elapsed;
        m_monitoringTimer.Interval = 10000;
        m_monitoringTimer.AutoReset = true;
        m_monitoringTimer.Start();
    }

    public void Dispose()
    {
        if (m_disposed)
            return;

        m_monitoringTimer.Stop();
        m_monitoringTimer.Dispose();
        m_disposed = true;
    }

    private void m_frameParser_ReceivedFrameImage(object sender, EventArgs<FundamentalFrameType, int> e)
    {
        // We track bytes received so that connection can be restarted if data is not flowing
        m_bytesReceived += e.Argument2;
    }

    private void m_monitoringTimer_Elapsed(object sender, EventArgs<DateTime> e)
    {
        if (m_bytesReceived == 0)
        {
            // If we've received no data in the last time-span, we restart connect cycle...
            OnStatusMessage(MessageLevel.Info, $"\r\nNo data received in {m_dataStreamMonitor.Interval / 1000.0D:0.0} seconds, restarting connect cycle...\r\n", "Connection Issues");
            m_frameParser.Stop();
            m_frameParser.Start();
        }

        m_bytesReceived = 0;
    }
}