using System; using System.Text; using Curtain.Net.Sockets.PLC.Model; namespace Curtain.Net.Sockets.PLC { /// /// Socket 客户端 /// public class SocketClient : PLCSocket where TClientModel : IClientModel, new() { #region 属性 /// /// 通信(接收)超时(毫秒) /// public int ReceiveTimeout { get; set; } /// /// 通信(发送)超时(毫秒) /// public int SendTimeout { get; set; } /// /// 主机地址 /// public string Host { get; protected set; } /// /// 主机端口 /// public int Port { get; protected set; } /// /// PLC通信模型 /// public TClientModel PLCModel { get; protected set; } #endregion #region 构造 /// /// Socket 客户端 /// /// 新实例 public SocketClient(bool newModel = false) { if (newModel) { PLCModel = new TClientModel(); } else { PLCModel = Model.ClientModel.CreateModel(); } this.ReceiveTimeout = this.PLCModel.ReceiveTimeout; this.SendTimeout = this.PLCModel.SendTimeout; } /// /// Socket 客户端 /// /// 新实例 public SocketClient(TClientModel model) { if (model == null) { throw new NullReferenceException("ClientSocket TPLCModel"); } PLCModel = model; this.ReceiveTimeout = this.PLCModel.ReceiveTimeout; this.SendTimeout = this.PLCModel.SendTimeout; } /// /// Socket 客户端 /// /// 主机地址 /// 主机端口 /// 新实例 public SocketClient(string host, int port, bool newModel = false) : this(newModel) { Host = host; Port = port; } /// /// Socket 客户端 /// /// 主机地址 /// 主机端口 /// 新实例 public SocketClient(string host, int port, TClientModel model) : this(model) { Host = host; Port = port; } #endregion #region Connect /// /// 连接PLC /// public virtual void Connect() { base.Connect(Host, Port); } /// /// 连接PLC /// /// 主机地址 /// 主机端口 public override void Connect(string host, int port) { Host = host; Port = port; this.Connect(); } /// /// Socket连接后PLC初始化 /// public override void OnSocketConnect() { PLCModel.OnSocketConnect(this); } #endregion #region Command /// /// 发送命令报文 /// /// /// protected virtual PLCResult SendByClient(byte[] data) { this.Socket.SendTimeout = this.SendTimeout; //return BeginSend(data); return Send(data); } /// /// 接收响应报文 /// /// /// protected virtual PLCResult ReceiveByClient(int length) { this.Socket.ReceiveTimeout = this.ReceiveTimeout; //return BeginReceive(length); return Receive(length); } /// /// 执行命令(不等待响应) /// /// 报文 /// public virtual PLCResult DoCommandOneWay(PLCMessage plc_m) { PLCResult plcResult = new PLCResult(plc_m); if (plc_m == null) { plcResult.Successed = false; plcResult.Message = "no plc message"; return plcResult; } plc_m.Host = Host; plc_m.Port = Port; try { if (plc_m.CommandBytes == null || plc_m.CommandBytes.Length == 0) { if (string.IsNullOrEmpty(plc_m.Command)) { plcResult.Successed = false; plcResult.Message = "no command"; return plcResult; } else { plc_m.CommandBytes = PLCModel.ToSendFromCommand(plc_m.Command); } } this.ThreadLock?.Lock(); this.Connect(); PLCResult result = SendByClient(plcResult.Data.CommandBytes); if (!result.Successed) { plcResult.SetValue(result); return plcResult; } } catch (Exception ex) { //this.Disconnect(); plcResult.Successed = false; plcResult.Message = ex.Message; plcResult.MessageDetail = ex.ToString(); } finally { if (this.ThreadLock != null && this.ThreadLock.Locked) { this.ThreadLock.Unlock(); } } return plcResult; } /// /// 执行命令 /// /// 报文 /// public virtual PLCResult DoCommand(PLCMessage plc_m) { PLCResult plcResult = new PLCResult(plc_m); if (plc_m == null) { plcResult.Successed = false; plcResult.Message = "no plc message"; return plcResult; } plc_m.Host = Host; plc_m.Port = Port; try { if (plc_m.CommandBytes == null || plc_m.CommandBytes.Length == 0) { if (string.IsNullOrEmpty(plc_m.Command)) { plcResult.Successed = false; plcResult.Message = "no command"; return plcResult; } else { plc_m.CommandBytes = PLCModel.ToSendFromCommand(plc_m.Command); } } this.ThreadLock?.Lock(); this.Connect(); PLCResult result = SendByClient(plcResult.Data.CommandBytes); if (!result.Successed) { plcResult.SetValue(result); return plcResult; } // 响应报文-头 int headLength = PLCModel.HeadLength; if (headLength < 1) { return plcResult; } PLCResult headResult = ReceiveByClient(headLength); plcResult.Data.HeadBytes = headResult.Data; plcResult.Data.Head = PLCModel.ToResponseFromReceive(headResult.Data); if (!headResult.Successed) { plcResult.SetValue(headResult); return plcResult; } if (!PLCModel.CheckHead(plc_m)) { plcResult.Successed = false; plcResult.Message = "response head error"; return plcResult; } // 响应报文-文本 int dataLength = PLCModel.GetContentLength(plcResult.Data); if (dataLength > 0) { PLCResult dataResult = ReceiveByClient(dataLength); plcResult.Data.ContentBytes = dataResult.Data; plcResult.Data.Content = PLCModel.ToResponseFromReceive(dataResult.Data); if (!dataResult.Successed) { plcResult.SetValue(dataResult); return plcResult; } //PLCModel.SetValueFromCommand(plcResult.Data); } if (plcResult.Data.PLCError) { plcResult.Successed = false; plcResult.Message = plcResult.Data.Head; plcResult.MessageDetail = plcResult.Data.Content; } } catch (Exception ex) { //this.Disconnect(); plcResult.Successed = false; plcResult.Message = ex.Message; plcResult.MessageDetail = ex.ToString(); } finally { if (this.ThreadLock != null && this.ThreadLock.Locked) { this.ThreadLock.Unlock(); } } return plcResult; } /// /// 执行命令 /// /// /// public virtual PLCResult DoCommand(Func func) { return DoCommand(func()); } #endregion #region Read /// /// 读取 /// /// /// /// /// public virtual PLCResult Read(char code, int number, int length = 1) { return DoCommand(PLCModel.GetReadMessage(code, number, length)); } /// /// 读取 /// /// /// /// /// public virtual PLCResult Read(string code, string number, int length = 1) { return DoCommand(PLCModel.GetReadMessage(code, number, length)); } /// /// 读取 /// /// /// /// public virtual PLCResult Read(string code, int length = 1) { return DoCommand(PLCModel.GetReadMessage(code, length)); } /// /// 读取 /// /// /// /// /// public virtual PLCResult Read(char code, int number, int length = 1) { //PLCResult> plcResult = ReadValue(code, number, length); //if (plcResult?.Successed ?? false) //{ // return new PLCResult(plcResult, plcResult.Data.Value); //} //return new PLCResult(plcResult); PLCResult plcResult = DoCommand(PLCModel.GetReadMessage(code, number, length)); if (plcResult.Successed) { PLCMessage p_value = (PLCMessage)plcResult.Data; PLCModel.SetReadValueFromBytes(p_value); return new PLCResult(plcResult, p_value.Value); } return new PLCResult(plcResult); } /// /// 读取 /// /// /// /// /// public virtual PLCResult Read(string code, string number, int length = 1) { //PLCResult> plcResult = ReadValue(code, number, length); //if (plcResult?.Successed ?? false) //{ // return new PLCResult(plcResult, plcResult.Data.Value); //} //return new PLCResult(plcResult); PLCResult plcResult = DoCommand(PLCModel.GetReadMessage(code, number, length)); if (plcResult.Successed) { PLCMessage p_value = (PLCMessage)plcResult.Data; PLCModel.SetReadValueFromBytes(p_value); return new PLCResult(plcResult, p_value.Value); } return new PLCResult(plcResult); } /// /// 读取 /// /// /// /// public virtual PLCResult Read(string code, int length = 1) { //PLCResult> plcResult = ReadValue(code, length); //if (plcResult?.Successed ?? false) //{ // return new PLCResult(plcResult, plcResult.Data.Value); //} //return new PLCResult(plcResult); PLCResult plcResult = DoCommand(PLCModel.GetReadMessage(code, length)); if (plcResult.Successed) { PLCMessage p_value = (PLCMessage)plcResult.Data; PLCModel.SetReadValueFromBytes(p_value); return new PLCResult(plcResult, p_value.Value); } return new PLCResult(plcResult); } /// /// 读取 /// /// /// /// /// public virtual PLCResult> ReadValue(char code, int number, int length = 1) { PLCResult plcResult = DoCommand(PLCModel.GetReadMessage(code, number, length)); if (plcResult.Successed) { PLCModel.SetReadValueFromBytes((PLCMessage)plcResult.Data); } return new PLCResult>(plcResult, (PLCMessage)plcResult.Data); } /// /// 读取 /// /// /// /// /// public virtual PLCResult> ReadValue(string code, string number, int length = 1) { PLCResult plcResult = DoCommand(PLCModel.GetReadMessage(code, number, length)); if (plcResult.Successed) { PLCModel.SetReadValueFromBytes((PLCMessage)plcResult.Data); } return new PLCResult>(plcResult, (PLCMessage)plcResult.Data); } /// /// 读取 /// /// /// /// public virtual PLCResult> ReadValue(string code, int length = 1) { PLCResult plcResult = DoCommand(PLCModel.GetReadMessage(code, length)); if (plcResult.Successed) { PLCModel.SetReadValueFromBytes((PLCMessage)plcResult.Data); } return new PLCResult>(plcResult, (PLCMessage)plcResult.Data); } #endregion #region Write /// /// 写入 /// /// /// /// /// /// /// public virtual PLCResult Write(char code, int number, TValue value, int length = 0) { return DoCommand(PLCModel.GetWriteMessage(code, number, value, length)); } /// /// 写入 /// /// /// /// /// /// /// public virtual PLCResult Write(string code, string number, TValue value, int length = 0) { return DoCommand(PLCModel.GetWriteMessage(code, number, value, length)); } /// /// 写入 /// /// /// /// /// /// public virtual PLCResult Write(string code, TValue value, int length = 0) { return DoCommand(PLCModel.GetWriteMessage(code, value, length)); } /// /// 写入 /// /// /// /// /// /// /// public virtual PLCResult Write(char code, int number, string value, Encoding encoding, int length = 0) { return DoCommand(PLCModel.GetWriteMessage(code, number, value, encoding, length)); } /// /// 写入 /// /// /// /// /// /// /// public virtual PLCResult Write(string code, string number, string value, Encoding encoding, int length = 0) { return DoCommand(PLCModel.GetWriteMessage(code, number, value, encoding, length)); } /// /// 写入 /// /// /// /// /// /// public virtual PLCResult Write(string code, string value, Encoding encoding, int length = 0) { return DoCommand(PLCModel.GetWriteMessage(code, value, encoding, length)); } #endregion #region Send /// /// 发送 /// /// /// public virtual PLCResult Send(string value) { return DoCommandOneWay(PLCModel.GetSendMessage(value)); } /// /// 发送 /// /// /// public virtual PLCResult SendByResult(string value) { return DoCommand(PLCModel.GetSendMessage(value)); } #endregion } }