/// <summary> /// 重新开始接收下一次的数据传递 /// </summary> /// <param name="session">网络状态</param> /// <param name="isProcess">是否触发数据处理</param> internal void ReBeginReceiveHead(AppSession session, bool isProcess) { try { byte[] head = session.BytesHead, Content = session.BytesContent; session.Clear( ); session.WorkSocket.BeginReceive(session.BytesHead, session.AlreadyReceivedHead, session.BytesHead.Length - session.AlreadyReceivedHead, SocketFlags.None, new AsyncCallback(HeadBytesReceiveCallback), session); // 检测是否需要数据处理 if (isProcess) { // 校验令牌 if (CheckRemoteToken(head)) { Content = HslProtocol.CommandAnalysis(head, Content); int protocol = BitConverter.ToInt32(head, 0); int customer = BitConverter.ToInt32(head, 4); // 转移到数据中心处理 DataProcessingCenter(session, protocol, customer, Content); } else { // 应该关闭网络通信 LogNet?.WriteWarn(ToString( ), StringResources.TokenCheckFailed); AppSessionRemoteClose(session); } } } catch (Exception ex) { SocketReceiveException(session, ex); LogNet?.WriteException(ToString( ), ex); } }
/// <summary> /// 处理请求接收连接后的方法 /// </summary> /// <param name="obj">Accpt对象</param> protected override void ThreadPoolLogin(object obj) { if (obj is Socket socket) { // 接收一条信息,指定当前请求的数据订阅信息的关键字 OperateResult <int, string> receive = ReceiveStringContentFromSocket(socket); if (!receive.IsSuccess) { return; } // 判断当前的关键字在服务器是否有消息发布 if (!IsPushGroupOnline(receive.Content2)) { SendStringAndCheckReceive(socket, 1, "当前订阅的关键字不存在"); LogNet?.WriteWarn(ToString( ), "当前订阅的关键字不存在"); socket?.Close( ); return; } SendStringAndCheckReceive(socket, 0, ""); // 允许发布订阅信息 AppSession session = new AppSession( ); session.KeyGroup = receive.Content2; session.WorkSocket = socket; try { session.IpEndPoint = (System.Net.IPEndPoint)socket.RemoteEndPoint; session.IpAddress = session.IpEndPoint.Address.ToString( ); } catch (Exception ex) { LogNet?.WriteException(ToString( ), "Ip信息获取失败", ex); } try { socket.BeginReceive(session.BytesHead, 0, session.BytesHead.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), session); } catch (Exception ex) { LogNet?.WriteException(ToString( ), "开启信息接收失败", ex); return; } LogNet?.WriteDebug(ToString( ), $"客户端 [ {session.IpEndPoint} ] 上线"); PushGroupClient push = GetPushGroupClient(receive.Content2); if (push != null) { System.Threading.Interlocked.Increment(ref onlineCount); push.AddPushClient(session); } } }
private void ReceiveCallBack(IAsyncResult ar) { if (ar.AsyncState is Socket socket) { try { int receive = socket.EndReceive(ar); OperateResult <byte[]> read = RedisHelper.ReceiveCommand(socket); if (!read.IsSuccess) { SocketReceiveException(null); return; } else { socket.BeginReceive(new byte[0], 0, 0, SocketFlags.None, new AsyncCallback(ReceiveCallBack), socket); } OperateResult <string[]> data = RedisHelper.GetStringsFromCommandLine(read.Content); if (!data.IsSuccess) { LogNet?.WriteWarn(data.Message); return; } if (data.Content[0].ToUpper() == "SUBSCRIBE") { return; } else if (data.Content[0].ToUpper( ) == "MESSAGE") { action?.Invoke(data.Content[1], data.Content[2]); } else { LogNet?.WriteWarn(data.Content[0]); } } catch (ObjectDisposedException) { // 通常是主动退出 return; } catch (Exception ex) { SocketReceiveException(ex); } } }
/// <summary> /// [自校验] 从套接字中接收文件头信息 /// </summary> /// <param name="socket"></param> /// <returns></returns> protected OperateResult <FileBaseInfo> ReceiveFileHeadFromSocket(Socket socket) { // 先接收文件头信息 OperateResult <int, string> receiveString = ReceiveStringContentFromSocket(socket); if (!receiveString.IsSuccess) { return(new OperateResult <FileBaseInfo>( ) { Message = receiveString.Message }); } // 判断文件是否存在 if (receiveString.Content1 == 0) { socket?.Close( ); LogNet?.WriteWarn(ToString( ), "对方文件不存在,无法接收!"); return(new OperateResult <FileBaseInfo>( ) { Message = StringResources.FileNotExist }); } OperateResult <FileBaseInfo> result = new OperateResult <FileBaseInfo>( ); result.Content = new FileBaseInfo( ); try { // 提取信息 Newtonsoft.Json.Linq.JObject json = Newtonsoft.Json.Linq.JObject.Parse(receiveString.Content2); result.Content.Name = SoftBasic.GetValueFromJsonObject(json, "FileName", ""); result.Content.Size = SoftBasic.GetValueFromJsonObject(json, "FileSize", 0L); result.Content.Tag = SoftBasic.GetValueFromJsonObject(json, "FileTag", ""); result.Content.Upload = SoftBasic.GetValueFromJsonObject(json, "FileUpload", ""); result.IsSuccess = true; } catch (Exception ex) { socket?.Close( ); result.Message = "提取信息失败," + ex.Message; } return(result); }
/// <summary> /// 检查网络套接字是否操作超时,需要对套接字进行封装 /// </summary> /// <param name="obj">通常是 <see cref="HslTimeOut"/> 对象 </param> protected void ThreadPoolCheckTimeOut(object obj) { if (obj is HslTimeOut timeout) { while (!timeout.IsSuccessful) { Thread.Sleep(100); if ((DateTime.Now - timeout.StartTime).TotalMilliseconds > timeout.DelayTime) { // 连接超时或是验证超时 if (!timeout.IsSuccessful) { LogNet?.WriteWarn(ToString( ), "Wait Time Out : " + timeout.DelayTime); timeout.Operator?.Invoke( ); timeout.WorkSocket?.Close( ); } break; } } } }
/// <summary> /// 接收到串口数据的时候触发 /// </summary> /// <param name="sender">串口对象</param> /// <param name="e">消息</param> private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) { System.Threading.Thread.Sleep(20); // 此处做个微小的延时,等待数据接收完成 byte[] buffer = new byte[1024]; int count = serialPort.Read(buffer, 0, serialPort.BytesToRead); byte[] receive = new byte[count]; Array.Copy(buffer, 0, receive, 0, count); if (receive.Length < 3) { LogNet?.WriteError(ToString( ), $"Uknown Data:" + BasicFramework.SoftBasic.ByteToHexString(receive, ' ')); return; } if (Serial.SoftCRC16.CheckCRC16(receive)) { byte[] modbusCore = ModbusRtuTransModbusCore(receive); if (!CheckModbusMessageLegal(modbusCore)) { // 指令长度验证错误,关闭网络连接 LogNet?.WriteError(ToString( ), $"Receive Nosense Modbus-tcp : " + BasicFramework.SoftBasic.ByteToHexString(receive, ' ')); return; } // LogNet?.WriteError( ToString( ), $"Success:" + BasicFramework.SoftBasic.ByteToHexString( receive, ' ' ) ); // 需要回发消息 byte[] copy = ModbusCoreTransModbusRtu(ReadFromModbusCore(modbusCore)); serialPort.Write(copy, 0, copy.Length); } else { LogNet?.WriteWarn("CRC Check Failed : " + BasicFramework.SoftBasic.ByteToHexString(receive, ' ')); } }
private void ThreadHeartCheck( ) { while (true) { Thread.Sleep(2000); try { for (int i = appSessions.Count - 1; i >= 0; i--) { if (appSessions[i] == null) { appSessions.RemoveAt(i); continue; } if ((DateTime.Now - appSessions[i].HeartTime).TotalSeconds > 1 * 8)//8次没有收到失去联系 { LogNet?.WriteWarn(ToString(), "心跳验证超时,强制下线:" + appSessions[i].IpAddress.ToString( )); TcpStateDownLine(appSessions[i], false, false); continue; } } } catch (Exception ex) { LogNet?.WriteException(ToString(), "心跳线程异常:", ex); } if (!IsStarted) { break; } } }
/// <summary> /// 登录后的处理方法 /// </summary> /// <param name="obj"></param> protected override void ThreadPoolLogin(object obj) { if (obj is Socket socket) { // 判断连接数是否超出规定 if (appSessions.Count > ConnectMax) { socket?.Close( ); LogNet?.WriteWarn(ToString(), StringResources.NetClientFull); return; } // 接收用户别名并验证令牌 OperateResult result = new OperateResult( ); OperateResult <int, string> readResult = ReceiveStringContentFromSocket(socket); if (!readResult.IsSuccess) { return; } // 登录成功 AppSession session = new AppSession( ) { WorkSocket = socket, LoginAlias = readResult.Content2, }; try { session.IpEndPoint = (IPEndPoint)socket.RemoteEndPoint; session.IpAddress = ((IPEndPoint)socket.RemoteEndPoint).Address.ToString( ); } catch (Exception ex) { LogNet?.WriteException(ToString( ), "客户端地址获取失败:", ex); } if (readResult.Content1 == 1) { // 电脑端客户端 session.ClientType = "Windows"; } else if (readResult.Content1 == 2) { // Android 客户端 session.ClientType = "Android"; } try { session.WorkSocket.BeginReceive(session.BytesHead, session.AlreadyReceivedHead, session.BytesHead.Length - session.AlreadyReceivedHead, SocketFlags.None, new AsyncCallback(HeadBytesReceiveCallback), session); TcpStateUpLine(session); Thread.Sleep(100); //留下一些时间进行反应 } catch (Exception ex) { //登录前已经出错 TcpStateClose(session); LogNet?.WriteException(ToString(), StringResources.NetClientLoginFailed, ex); } } }
/// <summary> /// 指令头接收方法 /// </summary> /// <param name="ar">异步状态信息</param> protected void HeadBytesReceiveCallback(IAsyncResult ar) { if (ar.AsyncState is AppSession session) { try { int receiveCount = session.WorkSocket.EndReceive(ar); if (receiveCount == 0) { // 断开了连接,需要做个处理,一个是直接关闭,另一个是触发下线 AppSessionRemoteClose(session); return; } else { session.AlreadyReceivedHead += receiveCount; } } catch (ObjectDisposedException) { // 不需要处理,来自服务器主动关闭 return; } catch (SocketException ex) { // 已经断开连接了 SocketReceiveException(session, ex); LogNet?.WriteException(ToString( ), ex); return; } catch (Exception ex) { // 其他乱七八糟的异常重新启用接收数据 ReBeginReceiveHead(session, false); LogNet?.WriteException(ToString( ), StringResources.SocketEndReceiveException, ex); return; } if (session.AlreadyReceivedHead < session.BytesHead.Length) { try { // 仍需要接收 session.WorkSocket.BeginReceive(session.BytesHead, session.AlreadyReceivedHead, session.BytesHead.Length - session.AlreadyReceivedHead, SocketFlags.None, new AsyncCallback(HeadBytesReceiveCallback), session); } catch (Exception ex) { SocketReceiveException(session, ex); LogNet?.WriteException(ToString( ), ex); } } else { // 接收完毕,校验令牌 if (!CheckRemoteToken(session.BytesHead)) { LogNet?.WriteWarn(ToString( ), StringResources.TokenCheckFailed); AppSessionRemoteClose(session); return; } int receive_length = BitConverter.ToInt32(session.BytesHead, session.BytesHead.Length - 4); session.BytesContent = new byte[receive_length]; if (receive_length > 0) { try { int receiveSize = session.BytesContent.Length - session.AlreadyReceivedContent; session.WorkSocket.BeginReceive(session.BytesContent, session.AlreadyReceivedContent, receiveSize, SocketFlags.None, new AsyncCallback(ContentReceiveCallback), session); } catch (Exception ex) { SocketReceiveException(session, ex); LogNet?.WriteException(ToString( ), ex); } } else { // 处理数据并重新启动接收 ReBeginReceiveHead(session, true); } } } }
private void AsyncCallback(IAsyncResult ar) { if (ar.AsyncState is AsyncStateOne state) { try { int received = state.WorkSocket.EndReceiveFrom(ar, ref state.UdpEndPoint); //释放连接关联 state.WorkSocket = null; //马上开始重新接收,提供性能保障 RefreshReceive(); //处理数据 if (received >= HslCommunicationCode.HeadByteLength) { //检测令牌 if (NetSupport.IsTwoBytesEquel(state.BytesContent, 12, KeyToken.ToByteArray(), 0, 16)) { state.IpEndPoint = (IPEndPoint)state.UdpEndPoint; int contentLength = BitConverter.ToInt32(state.BytesContent, HslCommunicationCode.HeadByteLength - 4); if (contentLength == received - HslCommunicationCode.HeadByteLength) { byte[] head = new byte[HslCommunicationCode.HeadByteLength]; byte[] content = new byte[contentLength]; Array.Copy(state.BytesContent, 0, head, 0, HslCommunicationCode.HeadByteLength); if (contentLength > 0) { Array.Copy(state.BytesContent, 32, content, 0, contentLength); } //解析内容 content = NetSupport.CommandAnalysis(head, content); int protocol = BitConverter.ToInt32(head, 0); int customer = BitConverter.ToInt32(head, 4); //丢给数据中心处理 DataProcessingCenter(state, protocol, customer, content); } else { //否则记录到日志 LogNet?.WriteWarn(LogHeaderText, $"接收到异常数据,应接收长度:{(BitConverter.ToInt32(state.BytesContent, 4) + 8)} 实际接收:{received}"); } } else { LogNet?.WriteWarn(LogHeaderText, StringResources.TokenCheckFailed); } } else { LogNet?.WriteWarn(LogHeaderText, $"接收到异常数据,长度不符合要求,实际接收:{received}"); } } catch (ObjectDisposedException ex) { //主程序退出的时候触发 } catch (Exception ex) { LogNet?.WriteException(LogHeaderText, StringResources.SocketEndReceiveException, ex); //重新接收,此处已经排除掉了对象释放的异常 RefreshReceive(); } finally { //state = null; } } }
private void AsyncCallback(IAsyncResult ar) { if (ar.AsyncState is AppSession session) { try { int received = session.WorkSocket.EndReceiveFrom(ar, ref session.UdpEndPoint); // 释放连接关联 session.WorkSocket = null; // 马上开始重新接收,提供性能保障 RefreshReceive( ); // 处理数据 if (received >= HslProtocol.HeadByteLength) { // 检测令牌 if (CheckRemoteToken(session.BytesContent)) { session.IpEndPoint = (IPEndPoint)session.UdpEndPoint; int contentLength = BitConverter.ToInt32(session.BytesContent, HslProtocol.HeadByteLength - 4); if (contentLength == received - HslProtocol.HeadByteLength) { byte[] head = new byte[HslProtocol.HeadByteLength]; byte[] content = new byte[contentLength]; Array.Copy(session.BytesContent, 0, head, 0, HslProtocol.HeadByteLength); if (contentLength > 0) { Array.Copy(session.BytesContent, 32, content, 0, contentLength); } // 解析内容 content = HslProtocol.CommandAnalysis(head, content); int protocol = BitConverter.ToInt32(head, 0); int customer = BitConverter.ToInt32(head, 4); // 丢给数据中心处理 DataProcessingCenter(session, protocol, customer, content); } else { // 否则记录到日志 LogNet?.WriteWarn(ToString(), $"Should Rece:{(BitConverter.ToInt32( session.BytesContent, 4 ) + 8)} Actual:{received}"); } } else { LogNet?.WriteWarn(ToString( ), StringResources.Language.TokenCheckFailed); } } else { LogNet?.WriteWarn(ToString( ), $"Receive error, Actual:{received}"); } } catch (ObjectDisposedException) { //主程序退出的时候触发 } catch (Exception ex) { LogNet?.WriteException(ToString( ), StringResources.Language.SocketEndReceiveException, ex); //重新接收,此处已经排除掉了对象释放的异常 RefreshReceive( ); } finally { //state = null; } } }
/// <summary> /// 处理请求接收连接后的方法 /// </summary> /// <param name="obj">Accpt对象</param> protected override void ThreadPoolLogin(object obj) { if (obj is Socket socket) { // 接收一条信息,指定当前请求的数据订阅信息的关键字 OperateResult <int, string> receive = ReceiveStringContentFromSocket(socket); if (!receive.IsSuccess) { return; } // 判断当前的关键字在服务器是否有消息发布 if (!IsPushGroupOnline(receive.Content2)) { SendStringAndCheckReceive(socket, 1, StringResources.Language.KeyIsNotExist); LogNet?.WriteWarn(ToString( ), StringResources.Language.KeyIsNotExist); socket?.Close( ); return; } SendStringAndCheckReceive(socket, 0, ""); // 允许发布订阅信息 AppSession session = new AppSession { KeyGroup = receive.Content2, WorkSocket = socket }; try { session.IpEndPoint = (System.Net.IPEndPoint)socket.RemoteEndPoint; session.IpAddress = session.IpEndPoint.Address.ToString( ); } catch (Exception ex) { LogNet?.WriteException(ToString( ), StringResources.Language.GetClientIpaddressFailed, ex); } try { socket.BeginReceive(session.BytesHead, 0, session.BytesHead.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), session); } catch (Exception ex) { LogNet?.WriteException(ToString( ), StringResources.Language.SocketReceiveException, ex); return; } LogNet?.WriteDebug(ToString( ), string.Format(StringResources.Language.ClientOnlineInfo, session.IpEndPoint)); PushGroupClient push = GetPushGroupClient(receive.Content2); if (push != null) { System.Threading.Interlocked.Increment(ref onlineCount); push.AddPushClient(session); dicSendCacheLock.Enter( ); if (dictSendHistory.ContainsKey(receive.Content2)) { if (isPushCacheAfterConnect) { SendString(session, dictSendHistory[receive.Content2]); } } dicSendCacheLock.Leave( ); } } }
/// <summary> /// 登录后的处理方法 /// </summary> /// <param name="obj"></param> protected override void ThreadPoolLogin(object obj) { if (obj is Socket socket) { // 判断连接数是否超出规定 if (All_sockets_connect.Count > ConnectMax) { socket?.Close(); LogNet?.WriteWarn(LogHeaderText, StringResources.NetClientFull); return; } // 接收用户别名并验证令牌 OperateResult result = new OperateResult(); if (!ReceiveStringFromSocket( socket, out int customer, out string login_alias, result, null )) { socket?.Close(); return; } // 登录成功 AsyncStateOne stateone = new AsyncStateOne() { WorkSocket = socket, LoginAlias = login_alias, IpEndPoint = (IPEndPoint)socket.RemoteEndPoint, IpAddress = ((IPEndPoint)socket.RemoteEndPoint).Address.ToString(), }; if (customer == 1) { // 电脑端客户端 stateone.ClientType = "Windows"; } else if (customer == 2) { // Android 客户端 stateone.ClientType = "Android"; } try { stateone.WorkSocket.BeginReceive(stateone.BytesHead, stateone.AlreadyReceivedHead, stateone.BytesHead.Length - stateone.AlreadyReceivedHead, SocketFlags.None, new AsyncCallback(HeadReceiveCallback), stateone); TcpStateUpLine(stateone); Thread.Sleep(500);//留下一些时间进行反应 } catch (Exception ex) { //登录前已经出错 TcpStateClose(stateone); LogNet?.WriteException(LogHeaderText, StringResources.NetClientLoginFailed, ex); } } }
/// <summary> /// 接收到串口数据的时候触发 /// </summary> /// <param name="sender">串口对象</param> /// <param name="e">消息</param> private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) { int rCount = 0; byte[] buffer = new byte[1024]; byte[] receive = null; while (true) { System.Threading.Thread.Sleep(20); // 此处做个微小的延时,等待数据接收完成 int count = serialPort.Read(buffer, rCount, serialPort.BytesToRead); rCount += count; if (count == 0) { break; } receive = new byte[rCount]; Array.Copy(buffer, 0, receive, 0, count); } if (receive == null) { return; } if (receive.Length < 3) { LogNet?.WriteError(ToString( ), $"Uknown Data:" + SoftBasic.ByteToHexString(receive, ' ')); return; } if (Serial.SoftCRC16.CheckCRC16(receive)) { byte[] modbusCore = SoftBasic.BytesArrayRemoveLast(receive, 2); if (!CheckModbusMessageLegal(modbusCore)) { // 指令长度验证错误,关闭网络连接 LogNet?.WriteError(ToString( ), $"Receive Nosense Modbus-rtu : " + SoftBasic.ByteToHexString(receive, ' ')); return; } // 验证站号是否一致 if (station >= 0 && station != modbusCore[0]) { LogNet?.WriteError(ToString( ), $"Station not match Modbus-rtu : " + SoftBasic.ByteToHexString(receive, ' ')); return; } // LogNet?.WriteError( ToString( ), $"Success:" + BasicFramework.SoftBasic.ByteToHexString( receive, ' ' ) ); // 需要回发消息 byte[] copy = ModbusInfo.PackCommandToRtu(ReadFromModbusCore(modbusCore)); serialPort.Write(copy, 0, copy.Length); if (IsStarted) { RaiseDataReceived(receive); } } else { LogNet?.WriteWarn("CRC Check Failed : " + SoftBasic.ByteToHexString(receive, ' ')); } }
private void ContentReveiveCallBack(IAsyncResult ar) { if (ar.AsyncState is ModBusState state) { try { int count = state.WorkSocket.EndReceive(ar); state.ContentReceivedLength += count; if (state.ContentReceivedLength < state.Content.Length) { // 数据不够,继续接收 state.WorkSocket.BeginReceive(state.Content, state.ContentReceivedLength, state.Content.Length - state.ContentReceivedLength, SocketFlags.None, new AsyncCallback(ContentReveiveCallBack), state); } else { // 内容接收完成,所有的数据接收结束 byte[] data = new byte[state.HeadByte.Length + state.Content.Length]; state.HeadByte.CopyTo(data, 0); state.Content.CopyTo(data, state.HeadByte.Length); state.Clear(); // 重新启动接收 state.WorkSocket.BeginReceive(state.HeadByte, state.HeadByteReceivedLength, state.HeadByte.Length, SocketFlags.None, new AsyncCallback(HeadReveiveCallBack), state); // 需要回发消息 byte[] copy = null; switch (data[7]) { case 0x01: { // 线圈读取 int address = data[8] * 256 + data[9]; int length = data[10] * 256 + data[11]; if (length > 2048) { length = 2048; // 线圈读取应该小于2048个 } bool[] read = ReadCoil((ushort)address, (ushort)length); byte[] buffer = BasicFramework.SoftBasic.BoolArrayToByte(read); copy = new byte[9 + buffer.Length]; Array.Copy(data, 0, copy, 0, 8); copy[4] = (byte)((copy.Length - 6) / 256); copy[5] = (byte)((copy.Length - 6) % 256); copy[8] = (byte)buffer.Length; Array.Copy(buffer, 0, copy, 9, buffer.Length); break; } case 0x02: { // 离散值读取,本服务器无效 copy = new byte[9]; Array.Copy(data, 0, copy, 0, 8); copy[4] = 0x00; copy[5] = 0x03; break; } case 0x03: { // 寄存器读取 int address = data[8] * 256 + data[9]; int length = data[10] * 256 + data[11]; if (length > 127) { length = 127; // 寄存器最大读取范围为127个 } byte[] buffer = ReadRegister((ushort)address, (ushort)length); copy = new byte[9 + buffer.Length]; Array.Copy(data, 0, copy, 0, 8); copy[4] = (byte)((copy.Length - 6) / 256); copy[5] = (byte)((copy.Length - 6) % 256); copy[8] = (byte)buffer.Length; Array.Copy(buffer, 0, copy, 9, buffer.Length); break; } case 0x05: { // 写单个线圈 int address = data[8] * 256 + data[9]; if (data[10] == 0xFF && data[11] == 0x00) { WriteCoil((ushort)address, true); } else if (data[10] == 0x00 && data[11] == 0x00) { WriteCoil((ushort)address, false); } copy = new byte[12]; Array.Copy(data, 0, copy, 0, 12); copy[4] = 0x00; copy[5] = 0x06; break; } case 0x06: { // 写单个寄存器 int address = data[8] * 256 + data[9]; WriteRegister((ushort)address, data[10], data[11]); copy = new byte[12]; Array.Copy(data, 0, copy, 0, 12); copy[4] = 0x00; copy[5] = 0x06; break; } case 0x0F: { // 写多个线圈 int address = data[8] * 256 + data[9]; int length = data[10] * 256 + data[11]; byte[] buffer = new byte[data.Length - 13]; Array.Copy(data, 13, buffer, 0, buffer.Length); bool[] value = BasicFramework.SoftBasic.ByteToBoolArray(buffer, length); WriteCoil((ushort)address, value); copy = new byte[12]; Array.Copy(data, 0, copy, 0, 12); copy[4] = 0x00; copy[5] = 0x06; break; } case 0x10: { // 写多个寄存器 int address = data[8] * 256 + data[9]; int length = data[10] * 256 + data[11]; byte[] buffer = new byte[data.Length - 13]; for (int i = 0; i < length; i++) { if ((2 * i + 14) < data.Length) { WriteRegister((ushort)(address + i), data[2 * i + 13], data[2 * i + 14]); } } copy = new byte[12]; Array.Copy(data, 0, copy, 0, 12); copy[4] = 0x00; copy[5] = 0x06; break; } default: { if (IsStarted) { LogNet?.WriteWarn(LogHeaderText, "Unknown Function Code:" + data[7]); } copy = new byte[12]; Array.Copy(data, 0, copy, 0, 12); copy[4] = 0x00; copy[5] = 0x06; break; } } // 回发数据 state.WorkSocket.BeginSend(copy, 0, size: copy.Length, socketFlags: SocketFlags.None, callback: new AsyncCallback(DataSendCallBack), state: state); // 通知处理消息 if (IsStarted) { OnDataReceived?.Invoke(data); } } } catch (Exception ex) { // 关闭连接,记录日志 state.WorkSocket?.Close(); state = null; if (IsStarted) { LogNet?.WriteException(LogHeaderText, "内容数据接收失败!", ex); } } } }
private void ModbusDataReveiveCallback(IAsyncResult ar) { if (ar.AsyncState is ModBusState state) { try { state.ContentReceivedLength += state.WorkSocket.EndReceive(ar); } catch (Exception ex) { // 关闭连接,记录日志 state.WorkSocket?.Close(); state = null; LogNet?.WriteException(LogHeaderText, "内容数据接收失败!", ex); return; } if (state.ContentReceivedLength < state.Content.Length) { // 数据不够,继续接收 state.WorkSocket.BeginReceive(state.Content, state.ContentReceivedLength, state.Content.Length - state.ContentReceivedLength, SocketFlags.None, new AsyncCallback(ModbusDataReveiveCallback), state); return; } // 数据接收完成 // 内容接收完成,所有的数据接收结束 byte[] data = new byte[state.HeadByte.Length + state.Content.Length]; state.HeadByte.CopyTo(data, 0); state.Content.CopyTo(data, state.HeadByte.Length); state.Clear(); if (data[7] == 0x01 || data[7] == 0x02 || data[7] == 0x03) { if (data.Length != 0x0C) { // 指令长度验证错误,关闭网络连接 state.WorkSocket?.Close(); state = null; LogNet?.WriteWarn(LogHeaderText, "Command length check failed!"); return; } } // 需要回发消息 byte[] copy = null; try { switch (data[7]) { case 0x01: { // 线圈读取 int address = data[8] * 256 + data[9]; int length = data[10] * 256 + data[11]; if (length > 2048) { length = 2048; // 线圈读取应该小于2048个 } bool[] read = ReadCoil((ushort)address, (ushort)length); byte[] buffer = BasicFramework.SoftBasic.BoolArrayToByte(read); copy = new byte[9 + buffer.Length]; Array.Copy(data, 0, copy, 0, 8); copy[4] = (byte)((copy.Length - 6) / 256); copy[5] = (byte)((copy.Length - 6) % 256); copy[8] = (byte)buffer.Length; Array.Copy(buffer, 0, copy, 9, buffer.Length); break; } case 0x03: { // 寄存器读取 int address = data[8] * 256 + data[9]; int length = data[10] * 256 + data[11]; if (length > 127) { length = 127; // 寄存器最大读取范围为127个 } byte[] buffer = ReadRegister((ushort)address, (ushort)length); copy = new byte[9 + buffer.Length]; Array.Copy(data, 0, copy, 0, 8); copy[4] = (byte)((copy.Length - 6) / 256); copy[5] = (byte)((copy.Length - 6) % 256); copy[8] = (byte)buffer.Length; Array.Copy(buffer, 0, copy, 9, buffer.Length); break; } case 0x05: { // 写单个线圈 int address = data[8] * 256 + data[9]; if (data[10] == 0xFF && data[11] == 0x00) { WriteCoil((ushort)address, true); } else if (data[10] == 0x00 && data[11] == 0x00) { WriteCoil((ushort)address, false); } copy = new byte[12]; Array.Copy(data, 0, copy, 0, 12); copy[4] = 0x00; copy[5] = 0x06; break; } case 0x06: { // 写单个寄存器 ushort address = (ushort)(data[8] * 256 + data[9]); short ValueOld = ReadShortRegister(address); // 写入到寄存器 WriteRegister(address, data[10], data[11]); short ValueNew = ReadShortRegister(address); // 触发写入请求 OnRegisterBeforWrite(address, ValueOld, ValueNew); copy = new byte[12]; Array.Copy(data, 0, copy, 0, 12); copy[4] = 0x00; copy[5] = 0x06; break; } case 0x0F: { // 写多个线圈 int address = data[8] * 256 + data[9]; int length = data[10] * 256 + data[11]; byte[] buffer = new byte[data.Length - 13]; Array.Copy(data, 13, buffer, 0, buffer.Length); bool[] value = BasicFramework.SoftBasic.ByteToBoolArray(buffer, length); WriteCoil((ushort)address, value); copy = new byte[12]; Array.Copy(data, 0, copy, 0, 12); copy[4] = 0x00; copy[5] = 0x06; break; } case 0x10: { // 写多个寄存器 int address = data[8] * 256 + data[9]; int length = data[10] * 256 + data[11]; byte[] buffer = new byte[data.Length - 13]; // 为了使服务器的数据订阅更加的准确,决定将设计改为等待所有的数据写入完成后,再统一触发订阅,2018年3月4日 20:56:47 MonitorAddress[] addresses = new MonitorAddress[length]; for (int i = 0; i < length; i++) { if ((2 * i + 14) < data.Length) { short ValueOld = ReadShortRegister((ushort)(address + i)); WriteRegister((ushort)(address + i), data[2 * i + 13], data[2 * i + 14]); short ValueNew = ReadShortRegister((ushort)(address + i)); // 触发写入请求 addresses[i] = new MonitorAddress( ) { Address = (ushort)(address + i), ValueOrigin = ValueOld, ValueNew = ValueNew }; } } // 所有数据都更改完成后,再触发消息 for (int i = 0; i < addresses.Length; i++) { OnRegisterBeforWrite(addresses[i].Address, addresses[i].ValueOrigin, addresses[i].ValueNew); } copy = new byte[12]; Array.Copy(data, 0, copy, 0, 12); copy[4] = 0x00; copy[5] = 0x06; break; } default: { copy = new byte[9]; Array.Copy(data, 0, copy, 0, 8); copy[4] = 0x00; copy[5] = 0x03; copy[7] = (byte)(data[7] + 0x80); copy[8] = 0x01; // 不支持的功能码 break; } } } catch (Exception ex) { state.WorkSocket?.Close( ); state = null; LogNet?.WriteException(LogHeaderText, ex); return; } try { // 管他是什么,先开始数据接收 // state.WorkSocket?.Close(); state.WorkSocket.BeginReceive(state.HeadByte, 0, 6, SocketFlags.None, new AsyncCallback(ModbusHeadReveiveCallback), state); } catch (Exception ex) { state.WorkSocket?.Close(); state = null; LogNet?.WriteException(LogHeaderText, "Send exception:", ex); return; } // 回发数据,先获取发送锁 state.hybirdLock.Enter(); state.WorkSocket.BeginSend(copy, 0, size: copy.Length, socketFlags: SocketFlags.None, callback: new AsyncCallback(DataSendCallBack), state: state); // 通知处理消息 if (IsStarted) { OnDataReceived?.Invoke(data); } } }
/// <summary> /// 当接收到了新的请求的时候执行的操作 /// </summary> /// <param name="socket">异步对象</param> /// <param name="endPoint">终结点</param> protected override void ThreadPoolLogin(Socket socket, IPEndPoint endPoint) { // 注册包 // 0x48 0x73 0x6E 0x00 0x17 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x30 0x31 0x00 0x00 0x00 0x00 0x00 0x00 0xC0 0xA8 0x00 0x01 0x17 0x10 // +------------+ +--+ +--+ +----------------------------------------------------+ +---------------------------+ +-----------------+ +-------+ // + 固定消息头 +备用 长度 DTU码 12345678901 (唯一标识) 登录密码(不受信的排除) Ip:192.168.0.1 端口10000 // +------------+ +--+ +--+ +----------------------------------------------------+ +---------------------------+ +-----------------+ // 返回 // 0x48 0x73 0x6E 0x00 0x01 0x00 // +------------+ +--+ +--+ +--+ // 固定消息头 备用 长度 结果代码 // 结果代码 // 0x00: 登录成功 // 0x01: DTU重复登录 // 0x02: DTU禁止登录 // 0x03: 密码验证失败 OperateResult <byte[]> check = ReceiveByMessage(socket, 5000, new AlienMessage( )); if (!check.IsSuccess) { return; } if (check.Content[4] != 0x17 || check.Content.Length != 0x1C) { socket?.Close( ); LogNet?.WriteWarn(ToString( ), "Length Check Failed"); return; } // 密码验证 bool isPasswrodRight = true; for (int i = 0; i < password.Length; i++) { if (check.Content[16 + i] != password[i]) { isPasswrodRight = false; break; } } string dtu = Encoding.ASCII.GetString(check.Content, 5, 11).Trim( ); // 密码失败的情况 if (!isPasswrodRight) { OperateResult send = Send(socket, GetResponse(StatusPasswodWrong)); if (send.IsSuccess) { socket?.Close( ); } LogNet?.WriteWarn(ToString( ), "Login Password Wrong, Id:" + dtu); return; } AlienSession session = new AlienSession( ) { DTU = dtu, Socket = socket, }; // 检测是否禁止登录 if (!IsClientPermission(session)) { OperateResult send = Send(socket, GetResponse(StatusLoginForbidden)); if (send.IsSuccess) { socket?.Close( ); } LogNet?.WriteWarn(ToString( ), "Login Forbidden, Id:" + session.DTU); return; } // 检测是否重复登录,不重复的话,也就是意味着登录成功了 if (IsClientOnline(session)) { OperateResult send = Send(socket, GetResponse(StatusLoginRepeat)); if (send.IsSuccess) { socket?.Close( ); } LogNet?.WriteWarn(ToString( ), "Login Repeat, Id:" + session.DTU); return; } else { OperateResult send = Send(socket, GetResponse(StatusOk)); if (!send.IsSuccess) { return; } } // 触发上线消息 OnClientConnected?.Invoke(this, session); }
private void ModbusHeadReveiveCallback(IAsyncResult ar) { if (ar.AsyncState is ModBusState state) { try { int receiveCount = state.WorkSocket.EndReceive(ar); if (receiveCount == 0) { state.WorkSocket?.Close( ); LogNet?.WriteDebug(ToString( ), $"客户端 [ {state.IpEndPoint} ] 下线"); return; } else { state.HeadByteReceivedLength += receiveCount; } } catch (Exception ex) { // 关闭连接,记录日志 state.WorkSocket?.Close( ); LogNet?.WriteException(ToString(), $"客户端 [ {state.IpEndPoint} ] 异常下线,消息子节接收失败!", ex); return; } try { if (state.HeadByteReceivedLength < state.HeadByte.Length) { // 数据不够,继续接收 state.WorkSocket.BeginReceive(state.HeadByte, state.HeadByteReceivedLength, state.HeadByte.Length - state.HeadByteReceivedLength, SocketFlags.None, new AsyncCallback(ModbusHeadReveiveCallback), state); return; } } catch (Exception ex) { state.WorkSocket?.Close( ); LogNet?.WriteException(ToString( ), $"客户端 [ {state.IpEndPoint} ] 异常下线,再次启动接收失败!", ex); return; } // 准备接收的数据长度 int ContentLength = state.HeadByte[4] * 256 + state.HeadByte[5]; // 第一次过滤,过滤掉不是Modbus Tcp协议的 if (state.HeadByte[2] == 0x00 && state.HeadByte[3] == 0x00 && ContentLength < 300) { try { // 头子节接收完成 state.Content = new byte[ContentLength]; state.ContentReceivedLength = 0; // 开始接收内容 state.WorkSocket.BeginReceive(state.Content, state.ContentReceivedLength, state.Content.Length - state.ContentReceivedLength, SocketFlags.None, new AsyncCallback(ModbusDataReveiveCallback), state); } catch (Exception ex) { state.WorkSocket?.Close( ); LogNet?.WriteException(ToString( ), $"客户端 [ {state.IpEndPoint} ] 异常下线,启动内容接收失败!", ex); return; } } else { // 关闭连接,记录日志 state.WorkSocket?.Close( ); LogNet?.WriteWarn(ToString(), $"客户端 [ {state.IpEndPoint} ] 下线,不是标准的Modbus协议!"); } } }
private void AsyncCallback(IAsyncResult ar) { if (ar.AsyncState is AppSession session) { try { int received = session.WorkSocket.EndReceiveFrom(ar, ref session.UdpEndPoint); // 马上开始重新接收,提供性能保障 RefreshReceive(); session.IpEndPoint = (IPEndPoint)session.UdpEndPoint; int contentLength = session.BytesContent[2] * 256 + session.BytesContent[3]; byte[] dtuNumArray = new byte[11]; byte[] publicNetworkArray = new byte[4]; byte[] publicPortArray = new byte[2]; if (contentLength > 0) { Array.Copy(session.BytesContent, 4, dtuNumArray, 0, 11); Array.Copy(session.BytesContent, 15, publicNetworkArray, 0, 4); Array.Copy(session.BytesContent, 19, publicPortArray, 0, 2); } if (session.BytesContent[0] == 0x7b) // 代表宏电DDP协议 { string dtuNum = Encoding.ASCII.GetString(dtuNumArray, 0, 11).Trim(); // 解析内容 if (session.BytesContent[1] == 0x01 && contentLength == 22) // 0x01 终端请求注册 { string publicNetwork = BasicFramework.SoftBasic.ByteToHexTenString(publicNetworkArray, '.'); // 终端内网IP int publicPort = Convert.ToInt32(BasicFramework.SoftBasic.ByteToHexString(publicPortArray), 16); //终端内网端口 SendBytesAsync(session, BuildDtuNumCommand(dtuNumArray)); LogNet?.WriteInfo(ToString(), $"请求注册 终端号码:{dtuNum} 终端公网IP:{session.IpEndPoint} 终端内网IP:{publicNetwork}:{publicPort}"); } if (session.BytesContent[1] == 0x02 && contentLength == 16) // 0x02 终端请求注销 { LogNet?.WriteInfo(ToString(), $"请求注销 终端号码:{dtuNum}"); } if (session.BytesContent[1] == 0x09) // 0x09 发送给DSC的用户数据包 { byte[] instructArray = new byte[session.BytesContent[18]]; // 接收的指令长度(不包含宏电数据头) Array.Copy(session.BytesContent, 16, instructArray, 0, session.BytesContent[18]); LogNet?.WriteInfo(ToString(), $"发送给DSC的用户数据包 终端号码:{dtuNum} 数据捕获:{BasicFramework.SoftBasic.ByteToHexString(instructArray, ' ')}"); } } else { LogNet?.WriteWarn(ToString(), $"数据捕获:{BasicFramework.SoftBasic.ByteToHexString(session.BytesContent, ' ')}"); } } catch (ObjectDisposedException) { //主程序退出的时候触发 } catch (Exception ex) { LogNet?.WriteException(ToString(), StringResources.Language.SocketEndReceiveException, ex); //重新接收,此处已经排除掉了对象释放的异常 RefreshReceive(); } finally { //state = null; } } }