using log4net; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Net.Sockets; using System.Text; using System.Threading; namespace bsmd.AIS2Service { internal class SerialTCPReader : IAISThread { private readonly string _host; private readonly uint _port; private readonly ConcurrentQueue _inputQueue; private bool _stopFlag = false; private TcpClient tcpSocket; private Thread _thread; private const int sleepRetry = 30000; private const int maxRetries = 3; private static readonly ILog _log = LogManager.GetLogger(typeof(SerialTCPReader)); public SerialTCPReader(string host, uint port, ConcurrentQueue inputQueue) { _host = host; _port = port; _inputQueue = inputQueue; } private void ReadData() { while (!_stopFlag) { if (this.tcpSocket == null || !this.tcpSocket.Connected) { if (!this.Connect()) { _log.Error("Cannot connect to datasource, stopping service"); this.FatalErrorOccurred?.Invoke(this, new EventArgs()); } } try { foreach (string line in ReadLines(this.tcpSocket.GetStream(), Encoding.ASCII)) { _inputQueue.Enqueue(line); if (_stopFlag) return; } } catch (Exception ex) { _log.WarnFormat("Exception occurred on serial reader: {0}", ex.Message); } } } private bool Connect() { int retryCounter = 0; while (retryCounter < maxRetries) { try { this.tcpSocket = new TcpClient(_host, (int)_port); _log.InfoFormat("TCP stream connected ({0}:{1})", _host, _port); return true; } catch (Exception ex) { retryCounter++; _log.WarnFormat("connect failed: {0}, retrying {1}", ex.Message, retryCounter); Thread.Sleep(sleepRetry); } } return false; } private static IEnumerable ReadLines(Stream source, Encoding encoding) { using(StreamReader reader = new StreamReader(source, encoding)) { string line; while((line = reader.ReadLine()) != null) { yield return line; } _log.InfoFormat("passed behind yield and closing StreamReader"); } } #region IAISThread implementation public event EventHandler FatalErrorOccurred; public void Start() { if (_thread != null) return; // may not run twice ThreadStart runReader = new ThreadStart(this.ReadData); _thread = new Thread(runReader); _thread.Start(); } public void Stop() { if(_thread == null) return; _stopFlag = true; _thread.Join(); _thread = null; } public string Name { get { return "Serial stream reader"; } } #endregion } }