ModbusTcpServer.cs 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using HslCommunication.Core;
  6. using HslCommunication;
  7. using HslCommunication.Core.Net;
  8. using System.Net.Sockets;
  9. namespace HslCommunication.ModBus
  10. {
  11. /// <summary>
  12. /// Modbus-tcp的虚拟服务器,支持线圈和寄存器的读写操作
  13. /// </summary>
  14. public class ModbusTcpServer : NetworkServerBase
  15. {
  16. #region Constructor
  17. /// <summary>
  18. /// 实例化一个Modbus Tcp的服务器,支持数据读写操作
  19. /// </summary>
  20. public ModbusTcpServer( )
  21. {
  22. Coils = new bool[65536];
  23. Register = new byte[65536 * 2];
  24. hybirdLockCoil = new SimpleHybirdLock( );
  25. hybirdLockRegister = new SimpleHybirdLock( );
  26. lock_trusted_clients = new SimpleHybirdLock( );
  27. subscriptions = new List<ModBusMonitorAddress>( );
  28. subcriptionHybirdLock = new SimpleHybirdLock( );
  29. byteTransform = new ReverseWordTransform( );
  30. }
  31. #endregion
  32. #region Private Method
  33. /// <summary>
  34. /// 判断操作线圈或是寄存器的是否发生了越界
  35. /// </summary>
  36. /// <param name="address">起始地址</param>
  37. /// <param name="length">数据长度</param>
  38. /// <returns>越界返回<c>True</c>,否则返回<c>False</c></returns>
  39. private bool IsAddressOverBoundary( ushort address, ushort length )
  40. {
  41. if ((address + length) >= ushort.MaxValue)
  42. {
  43. return true;
  44. }
  45. else
  46. {
  47. return false;
  48. }
  49. }
  50. #endregion
  51. #region Public Members
  52. /// <summary>
  53. /// 接收到数据的时候就行触发
  54. /// </summary>
  55. public event Action<byte[]> OnDataReceived;
  56. #endregion
  57. #region Data Pool
  58. // 数据池,用来模拟真实的Modbus数据区块
  59. private bool[] Coils; // 线圈池
  60. private SimpleHybirdLock hybirdLockCoil; // 线圈池的同步锁
  61. private byte[] Register; // 寄存器池
  62. private SimpleHybirdLock hybirdLockRegister; // 寄存器池同步锁
  63. private IByteTransform byteTransform;
  64. #endregion
  65. #region Coil Read Write
  66. /// <summary>
  67. /// 读取地址的线圈的通断情况
  68. /// </summary>
  69. /// <param name="address">起始地址</param>
  70. /// <returns><c>True</c>或是<c>False</c></returns>
  71. /// <exception cref="IndexOutOfRangeException"></exception>
  72. public bool ReadCoil( ushort address )
  73. {
  74. bool result = false;
  75. hybirdLockCoil.Enter( );
  76. result = Coils[address];
  77. hybirdLockCoil.Leave( );
  78. return result;
  79. }
  80. /// <summary>
  81. /// 批量读取地址的线圈的通断情况
  82. /// </summary>
  83. /// <param name="address">起始地址</param>
  84. /// <param name="length">读取长度</param>
  85. /// <returns><c>True</c>或是<c>False</c></returns>
  86. /// <exception cref="IndexOutOfRangeException"></exception>
  87. public bool[] ReadCoil( ushort address, ushort length )
  88. {
  89. bool[] result = new bool[length];
  90. hybirdLockCoil.Enter( );
  91. for (int i = address; i < address + length; i++)
  92. {
  93. if (i < ushort.MaxValue)
  94. {
  95. result[i - address] = Coils[i];
  96. }
  97. }
  98. hybirdLockCoil.Leave( );
  99. return result;
  100. }
  101. /// <summary>
  102. /// 写入线圈的通断值
  103. /// </summary>
  104. /// <param name="address">起始地址</param>
  105. /// <param name="data">是否通断</param>
  106. /// <returns><c>True</c>或是<c>False</c></returns>
  107. /// <exception cref="IndexOutOfRangeException"></exception>
  108. public void WriteCoil( ushort address, bool data )
  109. {
  110. hybirdLockCoil.Enter( );
  111. Coils[address] = data;
  112. hybirdLockCoil.Leave( );
  113. }
  114. /// <summary>
  115. /// 写入线圈数组的通断值
  116. /// </summary>
  117. /// <param name="address">起始地址</param>
  118. /// <param name="data">是否通断</param>
  119. /// <returns><c>True</c>或是<c>False</c></returns>
  120. /// <exception cref="IndexOutOfRangeException"></exception>
  121. public void WriteCoil( ushort address, bool[] data )
  122. {
  123. if (data == null) return;
  124. hybirdLockCoil.Enter( );
  125. for (int i = address; i < address + data.Length; i++)
  126. {
  127. if (i < ushort.MaxValue)
  128. {
  129. Coils[i] = data[i - address];
  130. }
  131. }
  132. hybirdLockCoil.Leave( );
  133. }
  134. #endregion
  135. #region Register Read
  136. /// <summary>
  137. /// 读取自定义的寄存器的值
  138. /// </summary>
  139. /// <param name="address">起始地址</param>
  140. /// <param name="length">数据长度</param>
  141. /// <exception cref="IndexOutOfRangeException"></exception>
  142. /// <returns>byte数组值</returns>
  143. public byte[] ReadRegister( ushort address, ushort length )
  144. {
  145. byte[] buffer = new byte[length * 2];
  146. hybirdLockRegister.Enter( );
  147. for (int i = 0; i < buffer.Length; i++)
  148. {
  149. buffer[i] = Register[address * 2 + i];
  150. }
  151. hybirdLockRegister.Leave( );
  152. return buffer;
  153. }
  154. /// <summary>
  155. /// 读取一个寄存器的值,返回类型short
  156. /// </summary>
  157. /// <param name="address">起始地址</param>
  158. /// <exception cref="IndexOutOfRangeException"></exception>
  159. /// <returns>short值</returns>
  160. public short ReadInt16( ushort address )
  161. {
  162. return byteTransform.TransInt16( ReadRegister( address, 1 ), 0 );
  163. }
  164. /// <summary>
  165. /// 批量读取寄存器的值
  166. /// </summary>
  167. /// <param name="address">起始地址</param>
  168. /// <param name="length">读取的short长度</param>
  169. /// <exception cref="IndexOutOfRangeException"></exception>
  170. /// <returns>short数组值</returns>
  171. public short[] ReadInt16( ushort address, ushort length )
  172. {
  173. short[] result = new short[length];
  174. for (int i = 0; i < length; i++)
  175. {
  176. result[i] = ReadInt16( (ushort)(address + i) );
  177. }
  178. return result;
  179. }
  180. /// <summary>
  181. /// 读取一个寄存器的值,返回类型为ushort
  182. /// </summary>
  183. /// <param name="address">起始地址</param>
  184. /// <exception cref="IndexOutOfRangeException"></exception>
  185. /// <returns>ushort值</returns>
  186. public ushort ReadUInt16( ushort address )
  187. {
  188. return byteTransform.TransUInt16( ReadRegister( address, 1 ), 0 );
  189. }
  190. /// <summary>
  191. /// 批量读取寄存器的值
  192. /// </summary>
  193. /// <param name="address">起始地址</param>
  194. /// <param name="length">读取长度</param>
  195. /// <exception cref="IndexOutOfRangeException"></exception>
  196. /// <returns>ushort数组</returns>
  197. public ushort[] ReadUInt16( ushort address, ushort length )
  198. {
  199. ushort[] result = new ushort[length];
  200. for (int i = 0; i < length; i++)
  201. {
  202. result[i] = ReadUInt16( (ushort)(address + i) );
  203. }
  204. return result;
  205. }
  206. /// <summary>
  207. /// 读取两个寄存器组成的int值
  208. /// </summary>
  209. /// <param name="address">起始地址</param>
  210. /// <exception cref="IndexOutOfRangeException"></exception>
  211. /// <returns>int值</returns>
  212. public int ReadInt32( ushort address )
  213. {
  214. return byteTransform.TransInt32( ReadRegister( address, 2 ), 0 );
  215. }
  216. /// <summary>
  217. /// 批量读取寄存器组成的int值
  218. /// </summary>
  219. /// <param name="address">起始地址</param>
  220. /// <param name="length">数组长度</param>
  221. /// <exception cref="IndexOutOfRangeException"></exception>
  222. /// <returns>int数组</returns>
  223. public int[] ReadInt32( ushort address, ushort length )
  224. {
  225. int[] result = new int[length];
  226. for (int i = 0; i < length; i++)
  227. {
  228. result[i] = ReadInt32( (ushort)(address + 2 * i) );
  229. }
  230. return result;
  231. }
  232. /// <summary>
  233. /// 读取两个寄存器组成的uint值
  234. /// </summary>
  235. /// <param name="address">起始地址</param>
  236. /// <exception cref="IndexOutOfRangeException"></exception>
  237. /// <returns></returns>
  238. public uint ReadUInt32( ushort address )
  239. {
  240. return byteTransform.TransUInt32( ReadRegister( address, 2 ), 0 );
  241. }
  242. /// <summary>
  243. /// 批量读取寄存器组成的uint值
  244. /// </summary>
  245. /// <param name="address">起始地址</param>
  246. /// <param name="length">数组长度</param>
  247. /// <exception cref="IndexOutOfRangeException"></exception>
  248. /// <returns></returns>
  249. public uint[] ReadUInt32( ushort address, ushort length )
  250. {
  251. uint[] result = new uint[length];
  252. for (int i = 0; i < length; i++)
  253. {
  254. result[i] = ReadUInt32( (ushort)(address + 2 * i) );
  255. }
  256. return result;
  257. }
  258. /// <summary>
  259. /// 读取两个寄存器组成的float值
  260. /// </summary>
  261. /// <param name="address">起始地址</param>
  262. /// <exception cref="IndexOutOfRangeException"></exception>
  263. /// <returns></returns>
  264. public float ReadFloat( ushort address )
  265. {
  266. return byteTransform.TransSingle( ReadRegister( address, 2 ), 0 );
  267. }
  268. /// <summary>
  269. /// 批量读取寄存器组成的float值
  270. /// </summary>
  271. /// <param name="address">起始地址</param>
  272. /// <param name="length">数组长度</param>
  273. /// <exception cref="IndexOutOfRangeException"></exception>
  274. /// <returns></returns>
  275. public float[] ReadFloat( ushort address, ushort length )
  276. {
  277. float[] result = new float[length];
  278. for (int i = 0; i < length; i++)
  279. {
  280. result[i] = ReadFloat( (ushort)(address + 2 * i) );
  281. }
  282. return result;
  283. }
  284. /// <summary>
  285. /// 读取四个寄存器组成的long值
  286. /// </summary>
  287. /// <param name="address">起始地址</param>
  288. /// <exception cref="IndexOutOfRangeException"></exception>
  289. /// <returns></returns>
  290. public long ReadInt64( ushort address )
  291. {
  292. return byteTransform.TransInt64( ReadRegister( address, 4 ), 0 );
  293. }
  294. /// <summary>
  295. /// 批量读取寄存器组成的long值
  296. /// </summary>
  297. /// <param name="address">起始地址</param>
  298. /// <param name="length">数组长度</param>
  299. /// <exception cref="IndexOutOfRangeException"></exception>
  300. /// <returns></returns>
  301. public long[] ReadInt64( ushort address, ushort length )
  302. {
  303. long[] result = new long[length];
  304. for (int i = 0; i < length; i++)
  305. {
  306. result[i] = ReadInt64( (ushort)(address + 4 * i) );
  307. }
  308. return result;
  309. }
  310. /// <summary>
  311. /// 读取四个寄存器组成的ulong值
  312. /// </summary>
  313. /// <param name="address">起始地址</param>
  314. /// <exception cref="IndexOutOfRangeException"></exception>
  315. /// <returns></returns>
  316. public ulong ReadUInt64( ushort address )
  317. {
  318. return byteTransform.TransUInt64( ReadRegister( address, 4 ), 0 );
  319. }
  320. /// <summary>
  321. /// 批量读取寄存器组成的ulong值
  322. /// </summary>
  323. /// <param name="address">起始地址</param>
  324. /// <param name="length">数组长度</param>
  325. /// <exception cref="IndexOutOfRangeException"></exception>
  326. /// <returns></returns>
  327. public ulong[] ReadUInt64( ushort address, ushort length )
  328. {
  329. ulong[] result = new ulong[length];
  330. for (int i = 0; i < length; i++)
  331. {
  332. result[i] = ReadUInt64( (ushort)(address + 4 * i) );
  333. }
  334. return result;
  335. }
  336. /// <summary>
  337. /// 读取四个寄存器组成的double值
  338. /// </summary>
  339. /// <param name="address">起始地址</param>
  340. /// <exception cref="IndexOutOfRangeException"></exception>
  341. /// <returns></returns>
  342. public double ReadDouble( ushort address )
  343. {
  344. return byteTransform.TransDouble( ReadRegister( address, 4 ), 0 );
  345. }
  346. /// <summary>
  347. /// 批量读取寄存器组成的double值
  348. /// </summary>
  349. /// <param name="address">起始地址</param>
  350. /// <param name="length">数组长度</param>
  351. /// <exception cref="IndexOutOfRangeException"></exception>
  352. /// <returns></returns>
  353. public double[] ReadDouble( ushort address, ushort length )
  354. {
  355. double[] result = new double[length];
  356. for (int i = 0; i < length; i++)
  357. {
  358. result[i] = ReadDouble( (ushort)(address + 4 * i) );
  359. }
  360. return result;
  361. }
  362. /// <summary>
  363. /// 读取ASCII字符串,长度为寄存器数量,最终的字符串长度为这个值的2倍
  364. /// </summary>
  365. /// <param name="address">起始地址</param>
  366. /// <param name="length">寄存器长度</param>
  367. /// <exception cref="IndexOutOfRangeException"></exception>
  368. /// <returns></returns>
  369. public string ReadString( ushort address, ushort length )
  370. {
  371. string str = string.Empty;
  372. hybirdLockRegister.Enter( );
  373. str = Encoding.ASCII.GetString( Register, address * 2, length * 2 );
  374. hybirdLockRegister.Leave( );
  375. return str;
  376. }
  377. #endregion
  378. #region Register Write
  379. /// <summary>
  380. /// 写入寄存器数据,指定字节数据
  381. /// </summary>
  382. /// <param name="address">起始地址</param>
  383. /// <param name="value">字节数据</param>
  384. public void Write( ushort address, byte[] value )
  385. {
  386. hybirdLockRegister.Enter( );
  387. for (int i = 0; i < value.Length; i++)
  388. {
  389. Register[address * 2 + i] = value[i];
  390. }
  391. hybirdLockRegister.Leave( );
  392. }
  393. /// <summary>
  394. /// 写入寄存器数据,指定字节数据
  395. /// </summary>
  396. /// <param name="address">起始地址</param>
  397. /// <param name="high">高位数据</param>
  398. /// <param name="low">地位数据</param>
  399. public void Write( ushort address, byte high, byte low )
  400. {
  401. Write( address, new byte[] { high, low } );
  402. }
  403. /// <summary>
  404. /// 往Modbus服务器中的指定寄存器写入数据
  405. /// </summary>
  406. /// <param name="address">起始地址</param>
  407. /// <param name="value">数据值</param>
  408. public void Write( ushort address, short value )
  409. {
  410. Write( address, byteTransform.TransByte( value ) );
  411. }
  412. /// <summary>
  413. /// 往Modbus服务器中的指定寄存器写入数组
  414. /// </summary>
  415. /// <param name="address">起始地址</param>
  416. /// <param name="value">数据值</param>
  417. public void Write( ushort address, short[] value )
  418. {
  419. if (value == null) return;
  420. Write( address, byteTransform.TransByte( value ) );
  421. }
  422. /// <summary>
  423. /// 往Modbus服务器中的指定寄存器写入数据
  424. /// </summary>
  425. /// <param name="address">起始地址</param>
  426. /// <param name="value">数据值</param>
  427. public void Write( ushort address, ushort value )
  428. {
  429. Write( address, byteTransform.TransByte( value ) );
  430. }
  431. /// <summary>
  432. /// 往Modbus服务器中的指定寄存器写入数组
  433. /// </summary>
  434. /// <param name="address">起始地址</param>
  435. /// <param name="value">数据值</param>
  436. public void Write( ushort address, ushort[] value )
  437. {
  438. if (value == null) return;
  439. Write( address, byteTransform.TransByte( value ) );
  440. }
  441. /// <summary>
  442. /// 往Modbus服务器中的指定寄存器写入数据
  443. /// </summary>
  444. /// <param name="address">起始地址</param>
  445. /// <param name="value">数据值</param>
  446. public void Write( ushort address, int value )
  447. {
  448. Write( address, byteTransform.TransByte( value ) );
  449. }
  450. /// <summary>
  451. /// 往Modbus服务器中的指定寄存器写入数组
  452. /// </summary>
  453. /// <param name="address">起始地址</param>
  454. /// <param name="value">数据值</param>
  455. public void Write( ushort address, int[] value )
  456. {
  457. if (value == null) return;
  458. Write( address, byteTransform.TransByte( value ) );
  459. }
  460. /// <summary>
  461. /// 往Modbus服务器中的指定寄存器写入数据
  462. /// </summary>
  463. /// <param name="address">起始地址</param>
  464. /// <param name="value">数据值</param>
  465. public void Write( ushort address, uint value )
  466. {
  467. Write( address, byteTransform.TransByte( value ) );
  468. }
  469. /// <summary>
  470. /// 往Modbus服务器中的指定寄存器写入数组
  471. /// </summary>
  472. /// <param name="address">起始地址</param>
  473. /// <param name="value">数据值</param>
  474. public void Write( ushort address, uint[] value )
  475. {
  476. if (value == null) return;
  477. Write( address, byteTransform.TransByte( value ) );
  478. }
  479. /// <summary>
  480. /// 往Modbus服务器中的指定寄存器写入数据
  481. /// </summary>
  482. /// <param name="address">起始地址</param>
  483. /// <param name="value">数据值</param>
  484. public void Write( ushort address, float value )
  485. {
  486. Write( address, byteTransform.TransByte( value ) );
  487. }
  488. /// <summary>
  489. /// 往Modbus服务器中的指定寄存器写入数组
  490. /// </summary>
  491. /// <param name="address">起始地址</param>
  492. /// <param name="value">数据值</param>
  493. public void Write( ushort address, float[] value )
  494. {
  495. if (value == null) return;
  496. Write( address, byteTransform.TransByte( value ) );
  497. }
  498. /// <summary>
  499. /// 往Modbus服务器中的指定寄存器写入数据
  500. /// </summary>
  501. /// <param name="address">起始地址</param>
  502. /// <param name="value">数据值</param>
  503. public void Write( ushort address, long value )
  504. {
  505. Write( address, byteTransform.TransByte( value ) );
  506. }
  507. /// <summary>
  508. /// 往Modbus服务器中的指定寄存器写入数组
  509. /// </summary>
  510. /// <param name="address">起始地址</param>
  511. /// <param name="value">数据值</param>
  512. public void Write( ushort address, long[] value )
  513. {
  514. if (value == null) return;
  515. Write( address, byteTransform.TransByte( value ) );
  516. }
  517. /// <summary>
  518. /// 往Modbus服务器中的指定寄存器写入数据
  519. /// </summary>
  520. /// <param name="address">起始地址</param>
  521. /// <param name="value">数据值</param>
  522. public void Write( ushort address, ulong value )
  523. {
  524. Write( address, byteTransform.TransByte( value ) );
  525. }
  526. /// <summary>
  527. /// 往Modbus服务器中的指定寄存器写入数组
  528. /// </summary>
  529. /// <param name="address">起始地址</param>
  530. /// <param name="value">数据值</param>
  531. public void Write( ushort address, ulong[] value )
  532. {
  533. if (value == null) return;
  534. Write( address, byteTransform.TransByte( value ) );
  535. }
  536. /// <summary>
  537. /// 往Modbus服务器中的指定寄存器写入数据
  538. /// </summary>
  539. /// <param name="address">起始地址</param>
  540. /// <param name="value">数据值</param>
  541. public void Write( ushort address, double value )
  542. {
  543. Write( address, byteTransform.TransByte( value ) );
  544. }
  545. /// <summary>
  546. /// 往Modbus服务器中的指定寄存器写入数组
  547. /// </summary>
  548. /// <param name="address">起始地址</param>
  549. /// <param name="value">数据值</param>
  550. public void Write( ushort address, double[] value )
  551. {
  552. if (value == null) return;
  553. Write( address, byteTransform.TransByte( value ) );
  554. }
  555. /// <summary>
  556. /// 往Mobus服务器中的指定寄存器写入字符串
  557. /// </summary>
  558. /// <param name="address">其实地址</param>
  559. /// <param name="value">ASCII编码的字符串的信息</param>
  560. public void Write(ushort address, string value)
  561. {
  562. Write( address, byteTransform.TransByte( value ) );
  563. }
  564. #endregion
  565. #region NetServer Override
  566. /// <summary>
  567. /// 当接收到了新的请求的时候执行的操作
  568. /// </summary>
  569. /// <param name="obj"></param>
  570. protected override void ThreadPoolLogin( object obj )
  571. {
  572. // 为了提高系统的响应能力,采用异步来实现,即时有数万台设备接入也能应付
  573. if (obj is Socket)
  574. {
  575. Socket socket = obj as Socket;
  576. ModBusState state = new ModBusState( )
  577. {
  578. WorkSocket = socket,
  579. };
  580. try
  581. {
  582. state.IpEndPoint = (System.Net.IPEndPoint)socket.RemoteEndPoint;
  583. state.IpAddress = state.IpEndPoint.Address.ToString( );
  584. }
  585. catch (Exception ex)
  586. {
  587. LogNet?.WriteException( ToString( ), "Ip信息获取失败", ex );
  588. }
  589. if(IsTrustedClientsOnly)
  590. {
  591. // 检查受信任的情况
  592. if(!CheckIpAddressTrusted( state.IpAddress ))
  593. {
  594. // 客户端不被信任,退出
  595. LogNet?.WriteDebug( ToString( ), $"客户端 [ {state.IpEndPoint} ] 不被信任,禁止登录!" );
  596. state.WorkSocket.Close( );
  597. return;
  598. }
  599. }
  600. LogNet?.WriteDebug( ToString( ), $"客户端 [ {state.IpEndPoint} ] 上线" );
  601. try
  602. {
  603. state.WorkSocket.BeginReceive( state.HeadByte, 0, 6, SocketFlags.None, new AsyncCallback( ModbusHeadReveiveCallback ), state );
  604. }
  605. catch (Exception ex)
  606. {
  607. state = null;
  608. state.WorkSocket.Close( );
  609. LogNet?.WriteException( ToString(), $"客户端 [ {state.IpEndPoint} ] 头子节接收失败!", ex );
  610. }
  611. }
  612. }
  613. #endregion
  614. #region Private Method
  615. /// <summary>
  616. /// 检测当前的Modbus接收的指定是否是合法的
  617. /// </summary>
  618. /// <param name="buffer"></param>
  619. /// <returns></returns>
  620. private bool CheckModbusMessageLegal( byte[] buffer )
  621. {
  622. if (buffer[7] == 0x01 || buffer[7] == 0x02 || buffer[7] == 0x03 || buffer[7] == 0x05 || buffer[7] == 0x06)
  623. {
  624. if (buffer.Length != 0x0C)
  625. {
  626. return false;
  627. }
  628. else
  629. {
  630. return true;
  631. }
  632. }
  633. else if (buffer[7] == 0x0F || buffer[7] == 0x10)
  634. {
  635. if (buffer.Length < 13)
  636. {
  637. return false;
  638. }
  639. else
  640. {
  641. if (buffer[12] == (buffer.Length - 13))
  642. {
  643. return true;
  644. }
  645. else
  646. {
  647. return false;
  648. }
  649. }
  650. }
  651. else
  652. {
  653. return true;
  654. }
  655. }
  656. private void ModbusHeadReveiveCallback( IAsyncResult ar )
  657. {
  658. if (ar.AsyncState is ModBusState)
  659. {
  660. ModBusState state = ar.AsyncState as ModBusState;
  661. try
  662. {
  663. int receiveCount = state.WorkSocket.EndReceive( ar );
  664. if (receiveCount == 0)
  665. {
  666. state.WorkSocket?.Close( );
  667. LogNet?.WriteDebug( ToString( ), $"客户端 [ {state.IpEndPoint} ] 下线" );
  668. return;
  669. }
  670. else
  671. {
  672. state.HeadByteReceivedLength += receiveCount;
  673. }
  674. }
  675. catch (Exception ex)
  676. {
  677. // 关闭连接,记录日志
  678. state.WorkSocket?.Close( );
  679. LogNet?.WriteException( ToString(), $"客户端 [ {state.IpEndPoint} ] 异常下线,消息子节接收失败!", ex );
  680. return;
  681. }
  682. try
  683. {
  684. if (state.HeadByteReceivedLength < state.HeadByte.Length)
  685. {
  686. // 数据不够,继续接收
  687. state.WorkSocket.BeginReceive( state.HeadByte, state.HeadByteReceivedLength, state.HeadByte.Length - state.HeadByteReceivedLength,
  688. SocketFlags.None, new AsyncCallback( ModbusHeadReveiveCallback ), state );
  689. return;
  690. }
  691. }
  692. catch(Exception ex)
  693. {
  694. state.WorkSocket?.Close( );
  695. LogNet?.WriteException( ToString( ), $"客户端 [ {state.IpEndPoint} ] 异常下线,再次启动接收失败!", ex );
  696. return;
  697. }
  698. // 准备接收的数据长度
  699. int ContentLength = state.HeadByte[4] * 256 + state.HeadByte[5];
  700. // 第一次过滤,过滤掉不是Modbus Tcp协议的
  701. if (state.HeadByte[2] == 0x00 &&
  702. state.HeadByte[3] == 0x00 &&
  703. ContentLength < 300)
  704. {
  705. try
  706. {
  707. // 头子节接收完成
  708. state.Content = new byte[ContentLength];
  709. state.ContentReceivedLength = 0;
  710. // 开始接收内容
  711. state.WorkSocket.BeginReceive( state.Content, state.ContentReceivedLength, state.Content.Length - state.ContentReceivedLength,
  712. SocketFlags.None, new AsyncCallback( ModbusDataReveiveCallback ), state );
  713. }
  714. catch(Exception ex)
  715. {
  716. state.WorkSocket?.Close( );
  717. LogNet?.WriteException( ToString( ), $"客户端 [ {state.IpEndPoint} ] 异常下线,启动内容接收失败!", ex );
  718. return;
  719. }
  720. }
  721. else
  722. {
  723. // 关闭连接,记录日志
  724. state.WorkSocket?.Close();
  725. LogNet?.WriteWarn(ToString(), $"客户端 [ {state.IpEndPoint} ] 下线,不是标准的Modbus协议!");
  726. }
  727. }
  728. }
  729. private void ModbusDataReveiveCallback( IAsyncResult ar )
  730. {
  731. if (ar.AsyncState is ModBusState)
  732. {
  733. ModBusState state = ar.AsyncState as ModBusState;
  734. try
  735. {
  736. state.ContentReceivedLength += state.WorkSocket.EndReceive( ar );
  737. if (state.ContentReceivedLength < state.Content.Length)
  738. {
  739. // 数据不够,继续接收
  740. state.WorkSocket.BeginReceive( state.Content, state.ContentReceivedLength, state.Content.Length - state.ContentReceivedLength,
  741. SocketFlags.None, new AsyncCallback( ModbusDataReveiveCallback ), state );
  742. return;
  743. }
  744. }
  745. catch (Exception ex)
  746. {
  747. // 关闭连接,记录日志
  748. state.WorkSocket?.Close( );
  749. LogNet?.WriteException( ToString(), $"客户端 [ {state.IpEndPoint} ] 下线,内容数据接收失败!", ex );
  750. return;
  751. }
  752. // 数据接收完成
  753. // 内容接收完成,所有的数据接收结束
  754. byte[] data = new byte[state.HeadByte.Length + state.Content.Length];
  755. state.HeadByte.CopyTo( data, 0 );
  756. state.Content.CopyTo( data, state.HeadByte.Length );
  757. state.Clear( );
  758. if (!CheckModbusMessageLegal( data ))
  759. {
  760. // 指令长度验证错误,关闭网络连接
  761. state.WorkSocket?.Close( );
  762. LogNet?.WriteError( ToString( ), $"客户端 [ {state.IpEndPoint} ] 下线,消息长度检查失败!" );
  763. return;
  764. }
  765. // 需要回发消息
  766. byte[] copy = null;
  767. switch (data[7])
  768. {
  769. case ModbusInfo.ReadCoil:
  770. {
  771. copy = ReadCoilBack( data ); break;
  772. }
  773. case ModbusInfo.ReadRegister:
  774. {
  775. copy = ReadRegisterBack( data ); break;
  776. }
  777. case ModbusInfo.WriteOneCoil:
  778. {
  779. copy = WriteOneCoilBack( data ); break;
  780. }
  781. case ModbusInfo.WriteOneRegister:
  782. {
  783. copy = WriteOneRegisterBack( data ); break;
  784. }
  785. case ModbusInfo.WriteCoil:
  786. {
  787. copy = WriteCoilsBack( data ); break;
  788. }
  789. case ModbusInfo.WriteRegister:
  790. {
  791. copy = WriteRegisterBack( data ); break;
  792. }
  793. default:
  794. {
  795. copy = CreateExceptionBack( data, ModbusInfo.FunctionCodeNotSupport ); break;
  796. }
  797. }
  798. try
  799. {
  800. // 管他是什么,先开始数据接收
  801. // state.WorkSocket?.Close();
  802. state.WorkSocket.BeginReceive( state.HeadByte, 0, 6, SocketFlags.None, new AsyncCallback( ModbusHeadReveiveCallback ), state );
  803. }
  804. catch (Exception ex)
  805. {
  806. state.WorkSocket?.Close( );
  807. LogNet?.WriteException( ToString( ), $"客户端 [ {state.IpEndPoint} ] 异常下线,重新接收消息失败!", ex );
  808. return;
  809. }
  810. // 回发数据,先获取发送锁
  811. state.hybirdLock.Enter( );
  812. try
  813. {
  814. state.WorkSocket.BeginSend( copy, 0, size: copy.Length, socketFlags: SocketFlags.None, callback: new AsyncCallback( DataSendCallBack ), state: state );
  815. }
  816. catch(Exception ex)
  817. {
  818. state.WorkSocket?.Close( );
  819. state.hybirdLock.Leave( );
  820. LogNet?.WriteException( ToString( ), $"客户端 [ {state.IpEndPoint} ] 异常下线,开始回发消息失败!", ex );
  821. return;
  822. }
  823. // 通知处理消息
  824. if (IsStarted) OnDataReceived?.Invoke( data );
  825. }
  826. }
  827. private void DataSendCallBack( IAsyncResult ar )
  828. {
  829. if (ar.AsyncState is ModBusState)
  830. {
  831. ModBusState state = ar.AsyncState as ModBusState;
  832. state.hybirdLock.Leave( );
  833. try
  834. {
  835. state.WorkSocket.EndSend( ar );
  836. }
  837. catch (Exception ex)
  838. {
  839. state.WorkSocket?.Close( );
  840. state = null;
  841. LogNet?.WriteException( ToString( ), $"客户端 [ {state.IpEndPoint} ] 异常下线,确认回发消息失败!", ex );
  842. }
  843. }
  844. }
  845. #endregion
  846. #region Function Process Center
  847. /// <summary>
  848. /// 创建特殊的功能标识,然后返回该信息
  849. /// </summary>
  850. /// <param name="modbus"></param>
  851. /// <param name="error"></param>
  852. /// <returns></returns>
  853. private byte[] CreateExceptionBack( byte[] modbus, byte error )
  854. {
  855. byte[] buffer = new byte[9];
  856. Array.Copy( modbus, 0, buffer, 0, 7 );
  857. buffer[4] = 0x00;
  858. buffer[5] = 0x03;
  859. buffer[7] = (byte)(modbus[7] + 0x80);
  860. buffer[8] = error;
  861. return buffer;
  862. }
  863. /// <summary>
  864. /// 创建返回消息
  865. /// </summary>
  866. /// <param name="modbus"></param>
  867. /// <param name="content"></param>
  868. /// <returns></returns>
  869. private byte[] CreateReadBack( byte[] modbus, byte[] content )
  870. {
  871. byte[] buffer = new byte[9 + content.Length];
  872. Array.Copy( modbus, 0, buffer, 0, 8 );
  873. buffer[4] = (byte)((buffer.Length - 6) / 256);
  874. buffer[5] = (byte)((buffer.Length - 6) % 256);
  875. buffer[8] = (byte)content.Length;
  876. Array.Copy( content, 0, buffer, 9, content.Length );
  877. return buffer;
  878. }
  879. /// <summary>
  880. /// 创建写入成功的反馈信号
  881. /// </summary>
  882. /// <param name="modbus"></param>
  883. /// <returns></returns>
  884. private byte[] CreateWriteBack(byte[] modbus)
  885. {
  886. byte[] buffer = new byte[12];
  887. Array.Copy( modbus, 0, buffer, 0, 12 );
  888. buffer[4] = 0x00;
  889. buffer[5] = 0x06;
  890. return buffer;
  891. }
  892. private byte[] ReadCoilBack(byte[] modbus )
  893. {
  894. try
  895. {
  896. ushort address = byteTransform.TransUInt16( modbus, 8 );
  897. ushort length = byteTransform.TransUInt16( modbus, 10 );
  898. // 越界检测
  899. if ((address + length) >= ushort.MaxValue)
  900. {
  901. return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeOverBound );
  902. }
  903. // 地址长度检测
  904. if(length > 2040)
  905. {
  906. return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeQuantityOver );
  907. }
  908. bool[] read = ReadCoil( address, length );
  909. byte[] buffer = BasicFramework.SoftBasic.BoolArrayToByte( read );
  910. return CreateReadBack( modbus, buffer );
  911. }
  912. catch(Exception ex)
  913. {
  914. LogNet?.WriteException( ToString( ), StringResources.ModbusTcpReadCoilException, ex );
  915. return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeReadWriteException );
  916. }
  917. }
  918. private byte[] ReadRegisterBack(byte[] modbus)
  919. {
  920. try
  921. {
  922. ushort address = byteTransform.TransUInt16( modbus, 8 );
  923. ushort length = byteTransform.TransUInt16( modbus, 10 );
  924. // 越界检测
  925. if ((address + length) >= ushort.MaxValue)
  926. {
  927. return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeOverBound );
  928. }
  929. // 地址长度检测
  930. if (length > 127)
  931. {
  932. return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeQuantityOver );
  933. }
  934. byte[] buffer = ReadRegister( address, length );
  935. return CreateReadBack( modbus, buffer );
  936. }
  937. catch (Exception ex)
  938. {
  939. LogNet?.WriteException( ToString( ), StringResources.ModbusTcpReadRegisterException, ex );
  940. return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeReadWriteException );
  941. }
  942. }
  943. private byte[] WriteOneCoilBack( byte[] modbus )
  944. {
  945. try
  946. {
  947. ushort address = byteTransform.TransUInt16( modbus, 8 );
  948. if (modbus[10] == 0xFF && modbus[11] == 0x00)
  949. {
  950. WriteCoil( address, true );
  951. }
  952. else if (modbus[10] == 0x00 && modbus[11] == 0x00)
  953. {
  954. WriteCoil( address, false );
  955. }
  956. return CreateWriteBack( modbus );
  957. }
  958. catch(Exception ex)
  959. {
  960. LogNet?.WriteException( ToString( ), StringResources.ModbusTcpWriteCoilException, ex );
  961. return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeReadWriteException );
  962. }
  963. }
  964. private byte[] WriteOneRegisterBack( byte[] modbus)
  965. {
  966. try
  967. {
  968. ushort address = byteTransform.TransUInt16( modbus, 8 );
  969. short ValueOld = ReadInt16( address );
  970. // 写入到寄存器
  971. Write( address, modbus[10], modbus[11] );
  972. short ValueNew = ReadInt16( address );
  973. // 触发写入请求
  974. OnRegisterBeforWrite( address, ValueOld, ValueNew );
  975. return CreateWriteBack( modbus );
  976. }
  977. catch(Exception ex)
  978. {
  979. LogNet?.WriteException( ToString( ), StringResources.ModbusTcpWriteRegisterException, ex );
  980. return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeReadWriteException );
  981. }
  982. }
  983. private byte[] WriteCoilsBack(byte[] modbus)
  984. {
  985. try
  986. {
  987. ushort address = byteTransform.TransUInt16( modbus, 8 );
  988. ushort length = byteTransform.TransUInt16( modbus, 10 );
  989. if ((address + length) > ushort.MaxValue)
  990. {
  991. return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeOverBound );
  992. }
  993. if(length > 2040)
  994. {
  995. return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeQuantityOver );
  996. }
  997. byte[] buffer = new byte[modbus.Length - 13];
  998. Array.Copy( modbus, 13, buffer, 0, buffer.Length );
  999. bool[] value = BasicFramework.SoftBasic.ByteToBoolArray( buffer, length );
  1000. WriteCoil( address, value );
  1001. return CreateWriteBack( modbus );
  1002. }
  1003. catch (Exception ex)
  1004. {
  1005. LogNet?.WriteException( ToString( ), StringResources.ModbusTcpWriteCoilException, ex );
  1006. return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeReadWriteException );
  1007. }
  1008. }
  1009. private byte[] WriteRegisterBack( byte[] modbus)
  1010. {
  1011. try
  1012. {
  1013. ushort address = byteTransform.TransUInt16( modbus, 8 );
  1014. ushort length = byteTransform.TransUInt16( modbus, 10 );
  1015. if ((address + length) > ushort.MaxValue)
  1016. {
  1017. return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeOverBound );
  1018. }
  1019. if (length > 127)
  1020. {
  1021. return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeQuantityOver );
  1022. }
  1023. byte[] buffer = new byte[modbus.Length - 13];
  1024. // 为了使服务器的数据订阅更加的准确,决定将设计改为等待所有的数据写入完成后,再统一触发订阅,2018年3月4日 20:56:47
  1025. MonitorAddress[] addresses = new MonitorAddress[length];
  1026. for (ushort i = 0; i < length; i++)
  1027. {
  1028. short ValueOld = ReadInt16( (ushort)(address + i) );
  1029. Write( (ushort)(address + i), modbus[2 * i + 13], modbus[2 * i + 14] );
  1030. short ValueNew = ReadInt16( (ushort)(address + i) );
  1031. // 触发写入请求
  1032. addresses[i] = new MonitorAddress( )
  1033. {
  1034. Address = (ushort)(address + i),
  1035. ValueOrigin = ValueOld,
  1036. ValueNew = ValueNew
  1037. };
  1038. }
  1039. // 所有数据都更改完成后,再触发消息
  1040. for (int i = 0; i < addresses.Length; i++)
  1041. {
  1042. OnRegisterBeforWrite( addresses[i].Address, addresses[i].ValueOrigin, addresses[i].ValueNew );
  1043. }
  1044. return CreateWriteBack( modbus );
  1045. }
  1046. catch (Exception ex)
  1047. {
  1048. LogNet?.WriteException( ToString( ), StringResources.ModbusTcpWriteRegisterException, ex );
  1049. return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeReadWriteException );
  1050. }
  1051. }
  1052. #endregion
  1053. #region Subscription Support
  1054. // 本服务器端支持指定地址的数据订阅器,目前仅支持寄存器操作
  1055. private List<ModBusMonitorAddress> subscriptions; // 数据订阅集合
  1056. private SimpleHybirdLock subcriptionHybirdLock; // 集合锁
  1057. /// <summary>
  1058. /// 新增一个数据监视的任务,针对的是寄存器
  1059. /// </summary>
  1060. /// <param name="monitor"></param>
  1061. public void AddSubcription( ModBusMonitorAddress monitor )
  1062. {
  1063. subcriptionHybirdLock.Enter( );
  1064. subscriptions.Add( monitor );
  1065. subcriptionHybirdLock.Leave( );
  1066. }
  1067. /// <summary>
  1068. /// 移除一个数据监视的任务
  1069. /// </summary>
  1070. /// <param name="monitor"></param>
  1071. public void RemoveSubcrption( ModBusMonitorAddress monitor )
  1072. {
  1073. subcriptionHybirdLock.Enter( );
  1074. subscriptions.Remove( monitor );
  1075. subcriptionHybirdLock.Leave( );
  1076. }
  1077. /// <summary>
  1078. /// 在数据变更后,进行触发是否产生订阅
  1079. /// </summary>
  1080. /// <param name="address">数据地址</param>
  1081. /// <param name="before"></param>
  1082. /// <param name="after"></param>
  1083. private void OnRegisterBeforWrite( ushort address, short before, short after )
  1084. {
  1085. subcriptionHybirdLock.Enter( );
  1086. for (int i = 0; i < subscriptions.Count; i++)
  1087. {
  1088. if (subscriptions[i].Address == address)
  1089. {
  1090. subscriptions[i].SetValue( after );
  1091. if (before != after)
  1092. {
  1093. subscriptions[i].SetChangeValue( before, after );
  1094. }
  1095. }
  1096. }
  1097. subcriptionHybirdLock.Leave( );
  1098. }
  1099. #endregion
  1100. #region Trust Client Only
  1101. private List<string> TrustedClients = null; // 受信任的客户端
  1102. private bool IsTrustedClientsOnly = false; // 是否启用仅仅受信任的客户端登录
  1103. private SimpleHybirdLock lock_trusted_clients; // 受信任的客户端的列表
  1104. /// <summary>
  1105. /// 设置并启动受信任的客户端登录并读写,如果为null,将关闭对客户端的ip验证
  1106. /// </summary>
  1107. /// <param name="clients">受信任的客户端列表</param>
  1108. public void SetTrustedIpAddress(List<string> clients)
  1109. {
  1110. lock_trusted_clients.Enter( );
  1111. if (clients != null)
  1112. {
  1113. TrustedClients = clients.Select( m =>
  1114. {
  1115. System.Net.IPAddress iPAddress = System.Net.IPAddress.Parse( m );
  1116. return iPAddress.ToString( );
  1117. } ).ToList( );
  1118. IsTrustedClientsOnly = true;
  1119. }
  1120. else
  1121. {
  1122. TrustedClients = new List<string>( );
  1123. IsTrustedClientsOnly = false;
  1124. }
  1125. lock_trusted_clients.Leave( );
  1126. }
  1127. /// <summary>
  1128. /// 检查该Ip地址是否是受信任的
  1129. /// </summary>
  1130. /// <param name="ipAddress">Ip地址信息</param>
  1131. /// <returns>是受信任的返回<c>True</c>,否则返回<c>False</c></returns>
  1132. private bool CheckIpAddressTrusted(string ipAddress)
  1133. {
  1134. if(IsTrustedClientsOnly)
  1135. {
  1136. bool result = false;
  1137. lock_trusted_clients.Enter( );
  1138. for (int i = 0; i < TrustedClients.Count; i++)
  1139. {
  1140. if(TrustedClients[i] == ipAddress)
  1141. {
  1142. result = true;
  1143. break;
  1144. }
  1145. }
  1146. lock_trusted_clients.Leave( );
  1147. return result;
  1148. }
  1149. else
  1150. {
  1151. return false;
  1152. }
  1153. }
  1154. /// <summary>
  1155. /// 获取受信任的客户端列表
  1156. /// </summary>
  1157. /// <returns></returns>
  1158. public string[] GetTrustedClients()
  1159. {
  1160. string[] result = new string[0];
  1161. lock_trusted_clients.Enter( );
  1162. if(TrustedClients != null)
  1163. {
  1164. result = TrustedClients.ToArray( );
  1165. }
  1166. lock_trusted_clients.Leave( );
  1167. return result;
  1168. }
  1169. #endregion
  1170. #region Object Override
  1171. /// <summary>
  1172. /// 获取本对象的字符串表示形式
  1173. /// </summary>
  1174. /// <returns></returns>
  1175. public override string ToString( )
  1176. {
  1177. return "ModbusTcpServer";
  1178. }
  1179. #endregion
  1180. }
  1181. }