Fins_Tcp.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. using ProtocalGeneral;
  2. namespace FinsTcp;
  3. public class Fins_Tcp : IDisposable
  4. {
  5. private FinsTcpBase? _Service;
  6. private ITcpConnectNority? _tcpConnect;
  7. private string _IP = string.Empty;
  8. private int _port = 0;
  9. private Timer? _reconnectTimer;
  10. private Timer? _heartBeatTimer;
  11. private volatile ushort _heartBeatMissCount = 0;
  12. private ushort _maxHeartBeatMissCount = 5;
  13. private Func<bool>? _heartBeatCallBack;
  14. public bool Initialize(ITcpConnectNority? tcpConnect)
  15. {
  16. if (this._Service is not null)
  17. return false;
  18. this._Service = new FinsTcpBase();
  19. this._tcpConnect = tcpConnect;
  20. return true;
  21. }
  22. public bool Connect(string IP, int port, Func<bool> func, ushort heartBeatMissCount = 5, short heartBeatInterval = 1000, int sendTimeout = 1000, int receiveTimeout = 1000)
  23. {
  24. if (this._Service is null)
  25. return false;
  26. this._IP = IP;
  27. this._port = port;
  28. try
  29. {
  30. if (!this._Service.Link(IP, port, sendTimeout, receiveTimeout))
  31. return false;
  32. this._tcpConnect?.Connect(IP, port);
  33. this.StartHeartBeat(func, heartBeatMissCount, heartBeatInterval);
  34. }
  35. catch
  36. {
  37. return false;
  38. }
  39. return true;
  40. }
  41. private bool StartHeartBeat(Func<bool> func, ushort missCount = 5, short interval_ms = 1000)
  42. {
  43. if (this._heartBeatTimer is not null)
  44. return false;
  45. if (this._Service is null)
  46. return false;
  47. if (func is null)
  48. return false;
  49. this._maxHeartBeatMissCount = missCount;
  50. this._heartBeatCallBack = func;
  51. this._heartBeatTimer = new(HeatBeaterTimerCallBack, func, 0, interval_ms);
  52. return true;
  53. }
  54. private void HeatBeaterTimerCallBack(object? state)
  55. {
  56. if (this._heartBeatCallBack is null)
  57. return;
  58. if (this._heartBeatCallBack.Invoke())
  59. return;
  60. if (++_heartBeatMissCount <= this._maxHeartBeatMissCount)
  61. return;
  62. this._heartBeatTimer?.Dispose();
  63. this._tcpConnect?.DisConnect(this._IP, this._port);
  64. StartAutoReconnectTimer();
  65. }
  66. private void StartAutoReconnectTimer()
  67. {
  68. this._heartBeatTimer?.Dispose();
  69. this._heartBeatTimer = null;
  70. this._heartBeatMissCount = 0;
  71. this._reconnectTimer = new(ReconnectTimerCallBack, null, 0, 3000);
  72. }
  73. private void ReconnectTimerCallBack(object? state)
  74. {
  75. this._Service?.Close();
  76. this._Service = null;
  77. this._heartBeatTimer?.Dispose();
  78. this.Initialize(this._tcpConnect);
  79. if (!this.Connect(this._IP, this._port, this._heartBeatCallBack!, this._maxHeartBeatMissCount))
  80. return;
  81. this._reconnectTimer?.Dispose();
  82. }
  83. public bool GetData<T>(string address, out T? data)
  84. {
  85. data = default;
  86. if (this._Service is null)
  87. return false;
  88. try
  89. {
  90. switch (Type.GetTypeCode(typeof(T)))
  91. {
  92. case TypeCode.Boolean:
  93. if (!this._Service.GetBitState(address, out short state))
  94. return false;
  95. data = (T)(object)state;
  96. return true;
  97. case TypeCode.Int16:
  98. if (!this._Service.ReadWord(address, out short s))
  99. return false;
  100. data = (T)(object)s;
  101. return true;
  102. case TypeCode.Int32:
  103. if (!this._Service.ReadInt32(address, out int i))
  104. return false;
  105. data = (T)(object)i;
  106. return true;
  107. case TypeCode.Single:
  108. if (!this._Service.ReadReal(address, out float f))
  109. return false;
  110. data = (T)(object)f;
  111. return true;
  112. default:
  113. return false;
  114. }
  115. }
  116. catch
  117. {
  118. return false;
  119. }
  120. }
  121. public bool SetData<T>(string address, T data) where T : new()
  122. {
  123. if (this._Service is null)
  124. return false;
  125. try
  126. {
  127. return data switch
  128. {
  129. bool b => this._Service.SetBitState(address, b ? BitState.ON : BitState.OFF),
  130. short s => this._Service.WriteWord(address, s),
  131. int i => this._Service.WriteInt32(address, i),
  132. float f => this._Service.WriteReal(address, f),
  133. _ => false
  134. };
  135. }
  136. catch
  137. {
  138. return false;
  139. }
  140. }
  141. #region Dispose
  142. private bool disposedValue;
  143. protected virtual void Dispose(bool disposing)
  144. {
  145. if (!disposedValue)
  146. {
  147. if (disposing)
  148. {
  149. this._Service?.Close();
  150. this._Service = null;
  151. this._heartBeatTimer?.Dispose();
  152. this._reconnectTimer?.Dispose();
  153. this._tcpConnect?.DisConnect(this._IP, this._port);
  154. this._heartBeatMissCount = 0;
  155. }
  156. disposedValue = true;
  157. }
  158. }
  159. public void Dispose()
  160. {
  161. // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
  162. Dispose(disposing: true);
  163. GC.SuppressFinalize(this);
  164. }
  165. #endregion
  166. }