康耐德C2000设备可配置作为客户端和服务端两种方式,本次介绍的是将其作为服务端(采用服务端的好处是采集器开关量主动推送给已建立连接的客户端,客户端只需建立一个长连接,实时监测服务端是否发送开关量数据过来)进行通信,通信方式采用TCP/IP协议,通过康耐德官方的【C2000设备管理监控工作站】进行设备的IP,port等配置即可建立通信。
客户端与服务端(C2000)通信的相关主要代码附上
- 因为是多台设备所以采用多线程分开运作,互不干涉
private void OpenC2000Connect() { try { ThreadForC2000_topStitchLine = new Thread(C2000DriveFor_topStitchLine); ThreadForC2000_topStitchLine.IsBackground = true; ThreadForC2000_getOffLine = new Thread(C2000DriveFor_getOffLine); ThreadForC2000_getOffLine.IsBackground = true; ThreadForC2000_assemblyLine = new Thread(C2000DriveFor_assemblyLine); ThreadForC2000_assemblyLine.IsBackground = true; ThreadForC2000_topStitchLine.Start(); ThreadForC2000_getOffLine.Start(); ThreadForC2000_assemblyLine.Start(); } catch { throw; } }
- 初始化Socket链接
private void Initialize_topStitchLineC2000() { try { IPAddress ip = IPAddress.Parse(C2000_topStitchLineIP); var ipe = new IPEndPoint(ip, port); SocketFor_topStitchLine.Connect(ipe); SocketFor_topStitchLine.BeginReceive(RecieveFor_topStitchLine, 0, RecieveFor_topStitchLine.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack_topStitchLine), null); } catch { throw; } } private void Initialize_getOffLineC2000() { try { IPAddress ip = IPAddress.Parse(C2000_getOffLineIP); var ipe = new IPEndPoint(ip, port); SocketFor_getOffLine.Connect(ipe); SocketFor_getOffLine.BeginReceive(RecieveFor_getOffLine, 0, RecieveFor_getOffLine.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack_getOffLine), null); } catch { throw; } } private void Initialize_assemblyLineC2000() { try { IPAddress ip = IPAddress.Parse(C2000_assemblyLineIP); var ipe = new IPEndPoint(ip, port); SocketFor_assemblyLine.Connect(ipe); SocketFor_assemblyLine.BeginReceive(RecieveFor_assemblyLine, 0, RecieveFor_assemblyLine.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack_assemblyLine), null); } catch { throw; } }
- 异步监视服务端返回值
private void ReceiveCallBack_topStitchLine(IAsyncResult IAR) { try { int REnd = SocketFor_topStitchLine.EndReceive(IAR); var cmd = RecieveFor_topStitchLine.ConvertToHexStringFromHexByte(REnd); var state = BLL.Common.Setting.RunningState.runing; if (cmd == DataSetCache.C2000_CMD.D1_runing || cmd == DataSetCache.C2000_CMD.D1D2D2_runing) state = BLL.Common.Setting.RunningState.runing; if (cmd == DataSetCache.C2000_CMD.D1D2 || cmd == DataSetCache.C2000_CMD.D1D2D1 || cmd == DataSetCache.C2000_CMD.D2) state = BLL.Common.Setting.RunningState.fault; if (cmd == DataSetCache.C2000_CMD.D1Off) state = BLL.Common.Setting.RunningState.stop; DataSetCache.Services.TopStitchInsert(state); SocketFor_topStitchLine.BeginReceive(RecieveFor_topStitchLine, 0, RecieveFor_topStitchLine.Length, 0, new AsyncCallback(ReceiveCallBack_topStitchLine), null); } catch (Exception ex) { Logger.Error(ex.Message); } } private void ReceiveCallBack_getOffLine(IAsyncResult IAR) { try { int REnd = SocketFor_getOffLine.EndReceive(IAR); var cmd = RecieveFor_getOffLine.ConvertToHexStringFromHexByte(REnd); var state = BLL.Common.Setting.RunningState.runing; if (cmd == DataSetCache.C2000_CMD.D1_runing || cmd == DataSetCache.C2000_CMD.D1D2D2_runing) state = BLL.Common.Setting.RunningState.runing; if (cmd == DataSetCache.C2000_CMD.D1D2 || cmd == DataSetCache.C2000_CMD.D1D2D1 || cmd == DataSetCache.C2000_CMD.D2) state = BLL.Common.Setting.RunningState.fault; if (cmd == DataSetCache.C2000_CMD.D1Off) state = BLL.Common.Setting.RunningState.stop; DataSetCache.Services.GetOffLineInsert(state); SocketFor_getOffLine.BeginReceive(RecieveFor_getOffLine, 0, RecieveFor_getOffLine.Length, 0, new AsyncCallback(ReceiveCallBack_getOffLine), null); } catch (Exception ex) { Logger.Error(ex.Message); } } private void ReceiveCallBack_assemblyLine(IAsyncResult IAR) { try { int REnd = SocketFor_assemblyLine.EndReceive(IAR); var cmd = RecieveFor_assemblyLine.ConvertToHexStringFromHexByte(REnd); var state = BLL.Common.Setting.RunningState.runing; if (cmd == DataSetCache.C2000_CMD.D1_runing || cmd == DataSetCache.C2000_CMD.D1D2D2_runing) state = BLL.Common.Setting.RunningState.runing; if (cmd == DataSetCache.C2000_CMD.D1D2 || cmd == DataSetCache.C2000_CMD.D1D2D1 || cmd == DataSetCache.C2000_CMD.D2) state = BLL.Common.Setting.RunningState.fault; if (cmd == DataSetCache.C2000_CMD.D1Off) state = BLL.Common.Setting.RunningState.stop; DataSetCache.Services.AssemblyLineInsert(state); SocketFor_assemblyLine.BeginReceive(RecieveFor_assemblyLine, 0, RecieveFor_assemblyLine.Length, 0, new AsyncCallback(ReceiveCallBack_assemblyLine), null); } catch (Exception ex) { Logger.Error(ex.Message); } }
在开发客户端通信的过程中碰到几点问题,在这里把遇到的问题以及解决方案介绍下:
- 因客户端安装在服务器上,设备安装在现场,现场下班就会断电,服务器是不会关机的,这就导致当现场断电采集器(服务端),第二天开机是,和客户端已经建立的连接客户端还记得,但是服务端已经不记得啦。客户端这个时候就很尴尬,连接不上服务端, 重连又告诉你,你已经有连接啦。怎么办?
解:
public void C2000Drive() { while (true) { try { if (C2000IP.PingIp()) { if (!SocketForLine.Connected) InitializeLineC2000(); timerC2000Line(); } else { if (SocketForLine.Connected) { SocketForLine.Close(); SocketForLine = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); } lbl_C2000Line.Image = Resources.black; } Thread.Sleep(5000); } catch (Exception ex) { Logger.Error(ex.Message); } } }
当服务端IP地址ping不同的时候,并且Socket连接仍然是Connected状态(不主动关闭,即使服务端断了,连接状态还是Connected,我擦,网都不通啦,还连接个啥啊)的情况下,手动关闭连接并重新实例化Socket对象(以备等明天上班再送电重连)。