Commit 928036f2 张东亮

1

1 个父辈 b3aef1cd
正在显示 37 个修改的文件 包含 3661 行增加62 行删除
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16 # Visual Studio Version 17
VisualStudioVersion = 16.0.30225.117 VisualStudioVersion = 17.3.32811.315
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "source\Common\Common.csproj", "{43CDD09E-FCF3-4960-A01D-3BBFE9933122}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "source\Common\Common.csproj", "{43CDD09E-FCF3-4960-A01D-3BBFE9933122}"
EndProject EndProject
...@@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LoadCSVLibrary", "source\Lo ...@@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LoadCSVLibrary", "source\Lo
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FeederLineClient", "source\FeederLineClient\FeederLineClient.csproj", "{0D2542F5-DD62-4352-82D0-383D9A045E74}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FeederLineClient", "source\FeederLineClient\FeederLineClient.csproj", "{0D2542F5-DD62-4352-82D0-383D9A045E74}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DL.IOModule", "source\DL.IOModule\DL.IOModule.csproj", "{F85A7412-B5B3-4291-A448-A10564602E1A}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
...@@ -39,6 +41,10 @@ Global ...@@ -39,6 +41,10 @@ Global
{0D2542F5-DD62-4352-82D0-383D9A045E74}.Debug|Any CPU.Build.0 = Debug|Any CPU {0D2542F5-DD62-4352-82D0-383D9A045E74}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0D2542F5-DD62-4352-82D0-383D9A045E74}.Release|Any CPU.ActiveCfg = Release|Any CPU {0D2542F5-DD62-4352-82D0-383D9A045E74}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0D2542F5-DD62-4352-82D0-383D9A045E74}.Release|Any CPU.Build.0 = Release|Any CPU {0D2542F5-DD62-4352-82D0-383D9A045E74}.Release|Any CPU.Build.0 = Release|Any CPU
{F85A7412-B5B3-4291-A448-A10564602E1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F85A7412-B5B3-4291-A448-A10564602E1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F85A7412-B5B3-4291-A448-A10564602E1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F85A7412-B5B3-4291-A448-A10564602E1A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="log4net, Version=1.2.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL"> <Reference Include="log4net, Version=2.0.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\..\dll\log4net.dll</HintPath> <HintPath>..\..\dll\log4net.dll</HintPath>
</Reference> </Reference>
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
<Reference Include="System.Configuration" /> <Reference Include="System.Configuration" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
<Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" /> <Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
...@@ -66,6 +67,9 @@ ...@@ -66,6 +67,9 @@
<ItemGroup> <ItemGroup>
<WCFMetadata Include="Service References\" /> <WCFMetadata Include="Service References\" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.
......
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="log4net" version="2.0.15" targetFramework="net40" />
</packages>
\ No newline at end of file \ No newline at end of file
...@@ -51,6 +51,15 @@ namespace OnlineStore.Common ...@@ -51,6 +51,15 @@ namespace OnlineStore.Common
AddToBox(msg, Color.Gray); AddToBox(msg, Color.Gray);
} }
} }
public static void error(ILog log, string errorMsg)
{
if (errorMsg.Trim().Equals(""))
{
return;
}
log.Error(errorMsg);
AddToBox(errorMsg, Color.Red);
}
public static void error(string errorMsg, int type) public static void error(string errorMsg, int type)
{ {
if (lastErrorLogTime.ContainsKey(type)) if (lastErrorLogTime.ContainsKey(type))
...@@ -69,7 +78,8 @@ namespace OnlineStore.Common ...@@ -69,7 +78,8 @@ namespace OnlineStore.Common
error(LOGGER, errorMsg); error(LOGGER, errorMsg);
} }
} }
public static void error(ILog log, string errorMsg, Exception ex = null)
public static void error(ILog log, string errorMsg, Exception ex)
{ {
if (errorMsg.Trim().Equals("")) if (errorMsg.Trim().Equals(""))
{ {
......
using DL.Utils;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace DL.IOModule
{
/// <summary>
/// 零点IO模块操作类
/// </summary>
public class AIOBOX
{
/// <summary>
/// 自动读取DIO委托
/// </summary>
/// <param name="box">AIOBOX</param>
/// <param name="sta"></param>
public delegate void DIO_Changed(AIOBOX box, Box_Sta[] sta);
/// <summary>
/// 自动读取AIO委托
/// </summary>
/// <param name="box">AIOBOX</param>
/// <param name="val"></param>
public delegate void AIO_Changed(AIOBOX box, int[] val);
/// <summary>
/// 自动读取DI事件触发
/// </summary>
public event DIO_Changed DI_Changed_Event;
/// <summary>
/// 自动读取DO事件触发
/// </summary>
public event DIO_Changed DO_Changed_Event;
/// <summary>
/// 自动读取AI事件触发
/// </summary>
public event AIO_Changed AI_Changed_Event;
/// <summary>
/// 设备地址
/// </summary>
private byte equipAddr = 255;
private Com.TCP.ModbusTCPMaster _client; //客户端
private bool _loop;
private Box_Sta[] _stateDI; //DI状态
private Box_Sta[] _stateDO; //DO状态
private int[] _valueAI; //AI模拟量
private int[] _valueAO; //AO模拟量
private List<byte> _receive;
private IOType _typeInput; //输入类型
private IOType _typeOutput; //输出类型
private byte[] _addressInput; //输入地址
private byte[] _addressOutput; //输出地址
private const int SEND_SLEEP = 50; //每条命令发送的间隔
private const int PORT = 502; //端口
private const int UPLOAD_TIME = 3000; //5秒
private Thread tSend; //发送命令处理
/// <summary>
/// 零点IO模块操作类
/// 数字信号输入,离散输入,支持功能码为02,
/// 模拟量输入,输入寄存器,支持功能码为04,
/// 数字信号输出,线圈,支持功能码为01,05,15
/// </summary>
/// <param name="logName"></param>
public AIOBOX()
{
_client = new Com.TCP.ModbusTCPMaster();
_client.ReceiveData += _client_ReceiveData;
}
/// <summary>
/// 收到的数据解析
/// </summary>
/// <param name="ip"></param>
/// <param name="port"></param>
/// <param name="requestInfo"></param>
/// <param name="data"></param>
private void _client_ReceiveData(string ip, int port, Com.TCP.RequestInfo requestInfo, byte[] data)
{
int idx = 0;
int count=data.Length;
try
{
if(requestInfo.FunCode==1)//ReadDO
{
Box_Sta[] staDO = new Box_Sta[_stateDO.Length];
for (int i = 0; i < count; i++)
{
int move = 0;
byte val = data[i];
for (int j = 0; j < 8; j++) //字节的0-7位
{
int n = (val & Convert.ToInt32(Math.Pow(2, move))) >> move;
staDO[idx++] = n == 1 ? Box_Sta.On : Box_Sta.Off;
move++;
}
}
Array.Copy(staDO, 0, _stateDO, 0, staDO.Length);
DO_Changed_Event?.Invoke(this, staDO);
}
else if (requestInfo.FunCode == 2) //ReadDI
{
Box_Sta[] staDI = new Box_Sta[_stateDI.Length];
for (int i = 0; i < count; i++)
{
int move = 0;
byte val = data[i];
for (int j = 0; j < 8; j++) //字节的0-7位
{
int n = (val & Convert.ToInt32(Math.Pow(2, move))) >> move;
staDI[idx++] = n == 1 ? Box_Sta.On : Box_Sta.Off;
move++;
}
}
Array.Copy(staDI, 0, _stateDI, 0, staDI.Length);
DI_Changed_Event?.Invoke(this, staDI);
}
}
catch (Exception ex)
{
LogUtil.Error("ReceiveData", ex);
}
}
/// <summary>
/// IP地址
/// </summary>
public string IP { set; get; } = "192.168.1.100";
/// <summary>
/// 输入主动上传
/// </summary>
public bool Upload { set; get; } = false;
/// <summary>
/// DI总数
/// </summary>
public int InputCount
{
get
{
if (_addressInput == null)
return 0;
else
return _addressInput.Length;
}
}
/// <summary>
/// DO总数
/// </summary>
public int OutputCount
{
get
{
if (_addressOutput == null)
return 0;
else
return _addressOutput.Length;
}
}
/// <summary>
/// 设置输入输出的类型
/// </summary>
/// <param name="input"></param>
/// <param name="inputCount"></param>
/// <param name="output"></param>
/// <param name="outputCount"></param>
public void SetType(IOType input, int inputCount, IOType output, int outputCount)
{
_typeInput = input;
_typeOutput = output;
byte n = 0;
_addressInput = new byte[inputCount];
for (int i = 0; i < inputCount; i++)
_addressInput[i] = n++;
_addressOutput = new byte[outputCount];
for (int i = 0; i < outputCount; i++)
_addressOutput[i] = n++;
_stateDI = new Box_Sta[inputCount];
_stateDO = new Box_Sta[outputCount];
_valueAI = new int[inputCount];
_valueAO = new int[outputCount];
}
/// <summary>
/// 连接
/// </summary>
/// <returns></returns>
public bool Connect()
{
_loop = true;
bool rtn = Utils.HttpHelper.CheckIP(IP);
if (!rtn) return false;
_client.Connect(IP, PORT);
tSend = new Thread(new ThreadStart(Send)) { Name = "Send" };
tSend.IsBackground = true;
tSend.Start();
_client.AddRequest(GetReadDO_Command());
_client.AddRequest(GetReadInput_Command());
return true;
}
/// <summary>
/// 关闭连接
/// </summary>
public void Close()
{
_loop = false;
try
{
if (_client != null)
{
_client.Close();
}
}
finally
{
_client = null;
}
}
/// <summary>
/// 相反状态(ON/OFF)
/// </summary>
/// <param name="sta"></param>
/// <returns></returns>
public Box_Sta ReverseStatus(Box_Sta sta)
{
return sta == Box_Sta.On ? Box_Sta.Off : Box_Sta.On;
}
/// <summary>
/// 相反状态(ON/OFF)
/// </summary>
/// <param name="sta"></param>
public void ReverseStatus(ref Box_Sta sta)
{
if (sta == Box_Sta.On)
sta = Box_Sta.Off;
else
sta = Box_Sta.On;
}
/// <summary>
/// 读取单个DI输入状态(ON/OFF)
/// </summary>
/// <param name="add">输入地址,从0开始</param>
/// <returns></returns>
public Box_Sta ReadDI(int add)
{
return _stateDI[add];
}
/// <summary>
/// 读取多个DI输入状态(ON/OFF)
/// </summary>
/// <param name="add">起始地址,从0开始</param>
/// <param name="count">数量</param>
/// <returns></returns>
public Box_Sta[] ReadDI(int add, int count)
{
Box_Sta[] sta = new Box_Sta[count];
Array.Copy(_stateDI, add, sta, 0, count);
return sta;
}
/// <summary>
/// 读取单个AI模拟量的值
/// </summary>
/// <param name="add">模拟量地址,从0开始</param>
/// <returns></returns>
public int ReadAI(int add)
{
return _valueAI[add];
}
/// <summary>
/// 读取多个AI模拟量的值
/// </summary>
/// <param name="add">起始地址,从0开始</param>
/// <param name="count">数量</param>
/// <returns></returns>
public int[] ReadAI(int add, int count)
{
int[] sta = new int[count];
Array.Copy(_valueAI, add, sta, 0, count);
return sta;
}
/// <summary>
/// 读取单个DO输出状态(ON/OFF)
/// </summary>
/// <param name="add">输出地址,从0开始</param>
/// <returns></returns>
public Box_Sta ReadDO(int add)
{
return _stateDO[add];
}
/// <summary>
/// 读取多个DO输出状态(ON/OFF)
/// </summary>
/// <param name="add">起始地址,从0开始</param>
/// <param name="count">数量</param>
/// <returns></returns>
public Box_Sta[] ReadDO(int add, int count)
{
Box_Sta[] sta = new Box_Sta[count];
Array.Copy(_stateDO, add, sta, 0, count);
return sta;
}
/// <summary>
/// 读取单个AO模拟量的值
/// </summary>
/// <param name="add">输出地址,从0开始</param>
/// <returns></returns>
public int ReadAO(int add)
{
return _valueAO[add];
}
/// <summary>
/// 读取多个AO模拟量的值
/// </summary>
/// <param name="add">起始地址,从0开始</param>
/// <param name="count">数量</param>
/// <returns></returns>
public int[] ReadAO(int add, int count)
{
int[] sta = new int[count];
Array.Copy(_valueAO, add, sta, 0, count);
return sta;
}
/// <summary>
/// 写入单个DO输出状态(ON/OFF)。
/// 写单个线圈,功能码05
/// </summary>
/// <param name="add">输出地址,从0开始</param>
/// <param name="sta"></param>
/// <returns></returns>
public bool WriteDO(int add, Box_Sta sta)
{
try
{
Com.TCP.RequestInfo request = new Com.TCP.RequestInfo();
request.StartAddr = _addressOutput[add];//起始地址
request.FunCode = 5;//功能码
request.EquipAddr = equipAddr;
request.CountOrValue = sta.Equals(Box_Sta.On) ? 1 : 0; //值
_client.AddRequest(request);
_client.AddRequest(GetReadDO_Command());
return true;
}
catch (Exception ex)
{
LogUtil.Error("WriteDO", ex);
return false;
}
}
/// <summary>
/// 写入多个DO输出状态(ON/OFF)
/// 写多个线圈,功能码15
/// </summary>
/// <param name="add">起始地址</param>
/// <param name="sta">对应的状态</param>
/// <returns></returns>
public bool WriteDO(int add, Box_Sta[] sta)
{
try
{
Com.TCP.RequestInfo request = new Com.TCP.RequestInfo();
request.StartAddr = _addressOutput[add];//起始地址
request.FunCode = 15;//功能码
request.EquipAddr = equipAddr;
request.CountOrValue = sta.Length; //个数
request.Values = Com.Protocol.Modbus.Register.GetValuesWithMultiMode(GetValues(sta));
_client.AddRequest(request);
_client.AddRequest(GetReadDO_Command());
return true;
}
catch (Exception ex)
{
LogUtil.Error("WriteDO", ex);
return false;
}
}
int[] GetValues(Box_Sta[] sta)
{
int[] tmp = new int[sta.Length];
for (int i = 0; i < sta.Length; i++)
{
tmp[i] = sta[i].Equals(Box_Sta.On) ? 1 : 0;
}
return tmp;
}
/// <summary>
/// 发送命令线程
/// </summary>
private void Send()
{
bool shift = true; //切换
int time = UPLOAD_TIME; //上传时间
while (_loop)
{
Com.TCP.RequestInfo request = null;
if (Upload) //主动上传
{
time += SEND_SLEEP;
if (time >= UPLOAD_TIME)
{
request = GetReadInput_Command();
time = 0;
}
else
{
//2020年6月11日
//buff = GetReadDO_Command();
Thread.Sleep(SEND_SLEEP);
continue;
}
}
else
{
if (shift)
request = GetReadInput_Command();
else
request = GetReadDO_Command();
shift = !shift;
}
_client.AddRequest(request);
Thread.Sleep(SEND_SLEEP);
}
}
/// <summary>
/// 读取输入
/// 数字信号输入,功能码为02,读离散输入
/// 模拟量输入,功能码为04,读输入寄存器
/// </summary>
/// <returns></returns>
private Com.TCP.RequestInfo GetReadInput_Command()
{
Com.TCP.RequestInfo request = new Com.TCP.RequestInfo();
request.StartAddr = _addressInput[0];//起始地址
//功能码
if (_typeInput == IOType.DI)
request.FunCode = 2;
else if (_typeInput == IOType.AI)
request.FunCode = 4;
request.EquipAddr = equipAddr;
request.CountOrValue = _addressInput.Length; //个数
return request;
}
/// <summary>
/// 读取DO,功能码01,读单个线圈
/// </summary>
/// <returns></returns>
private Com.TCP.RequestInfo GetReadDO_Command()
{
return new Com.TCP.RequestInfo()
{
StartAddr = _addressOutput[0],//起始地址
FunCode = 1,//功能码
EquipAddr = equipAddr,
CountOrValue = _addressOutput.Length //个数
};
}
}
}
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace DL.Com
{
public class ComHelper
{
static UdpClient broadcastClient; //广播客户端
static IPEndPoint broadcastEndPoint; //广播远程节点
static byte[] broadcastBuffer; //远程返回数据
/// <summary>
/// 自动获取IP地址,未连接前使用,必须在同一网段
/// </summary>
/// <param name="localIP">本地IP地址</param>
/// <returns></returns>
public static bool AutoIP(string localIP,out string ip)
{
ip = "";
try
{
IPEndPoint local = new IPEndPoint(IPAddress.Parse(localIP), 55654);
broadcastClient = new UdpClient(local);
broadcastBuffer = null;
Thread tTemp = new Thread(new ThreadStart(GetIP));
tTemp.Start();
broadcastEndPoint = new IPEndPoint(IPAddress.Parse("255.255.255.255"), 1024);
byte[] dgram = new byte[] { 0x05, 0x00, 0x07, 0x00, 0x00, 0xC1, 0x59 };
broadcastClient.Send(dgram, dgram.Length, broadcastEndPoint);
Thread.Sleep(1000);
tTemp.Abort();
broadcastClient.Close();
//ErrInfo = "无法访问";
if (broadcastBuffer == null) return false;
if (broadcastBuffer[0] != 0x3B) return false;
byte[] buff = new byte[broadcastBuffer[7]];
Array.Copy(broadcastBuffer, 9, buff, 0, buff.Length);
ip = buff[buff.Length - 12] + "." + buff[buff.Length - 11] + "." + buff[buff.Length - 10] + "." + buff[buff.Length - 9];
//ErrInfo = "OK";
return true;
}
catch (Exception ex)
{
return false;
}
}
/// <summary>
/// 获取目标IP地址
/// </summary>
static void GetIP()
{
broadcastBuffer = broadcastClient.Receive(ref broadcastEndPoint);
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{F85A7412-B5B3-4291-A448-A10564602E1A}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DL.IOModule</RootNamespace>
<AssemblyName>DL.IOModule</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="log4net, Version=2.0.8.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\3D-DoubleLineClient\dll\log4net.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\dll\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="AIOBOX\AIOBOX.cs" />
<Compile Include="CommHelper.cs" />
<Compile Include="HttpHelper.cs" />
<Compile Include="IOState.cs" />
<Compile Include="IOType.cs" />
<Compile Include="JsonHelper.cs" />
<Compile Include="LogUtil.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Protocol\Modbus\CoilRegister.cs" />
<Compile Include="Protocol\Modbus\DataFrame.cs" />
<Compile Include="Protocol\Modbus\DiscreteInputRegister.cs" />
<Compile Include="Protocol\Modbus\HoldingRegister.cs" />
<Compile Include="Protocol\Modbus\InputRegister.cs" />
<Compile Include="Protocol\Modbus\Register.cs" />
<Compile Include="StringHelper.cs" />
<Compile Include="TCP\ModbusTCPMaster.cs" />
<Compile Include="TCP\TcpClient.cs" />
<Compile Include="TCP\TcpServer.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Protocol\Modbus\_system~.ini" />
<None Include="Protocol\_system~.ini" />
<None Include="TCP\_system~.ini" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Common\Common.csproj">
<Project>{43CDD09E-FCF3-4960-A01D-3BBFE9933122}</Project>
<Name>Common</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
\ No newline at end of file \ No newline at end of file
using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DL.Utils
{
public class HttpHelper
{
/// <summary>
/// 检查IP是否合法
/// </summary>
/// <param name="ip"></param>
/// <returns></returns>
public static bool CheckIP(string ip,string name="")
{
//IP合法
string pattern = @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$";
bool rtn = System.Text.RegularExpressions.Regex.IsMatch(ip, pattern);
if (!rtn)
{
LogUtil.Error($"【{name}】非法的IP地址:" + ip);
return false;
}
return true;
}
/// <summary>
/// Ping指定IP
/// </summary>
/// <param name="ip"></param>
/// <returns></returns>
public static bool PingIP(string ip)
{
//Ping服务端
try
{
System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
System.Net.NetworkInformation.PingReply result = ping.Send(ip, 2000);
ping.Dispose();
if (result.Status != System.Net.NetworkInformation.IPStatus.Success)
{
return false;
}
return true;
}
catch (Exception ex)
{
LogUtil.Error($"PingIP{ip}:", ex);
return false;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace DL.IOModule
{
public enum Box_Sta : byte
{
/// <summary>
/// 断开,关闭,低电平
/// </summary>
Off,
/// <summary>
/// 闭合,打开,高电平
/// </summary>
On
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace DL.IOModule
{
/// <summary>
/// IO模块类型
/// </summary>
public enum IOType : byte
{
/// <summary>
/// 数字信号输入
/// </summary>
DI,
/// <summary>
/// 数字信号输出
/// </summary>
DO,
/// <summary>
/// 模拟量输入
/// </summary>
AI,
/// <summary>
/// 模拟量输出
/// </summary>
AO
}
}
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
namespace DL.Utils
{
/// <summary>
/// Json帮助类
/// </summary>
public class JsonHelper
{
/// <summary>
/// 将对象序列化为JSON格式
/// </summary>
/// <param name="o">对象</param>
/// <returns>json字符串</returns>
public static string SerializeObject(object o)
{
string json = JsonConvert.SerializeObject(o);
return json;
}
/// <summary>
/// 解析JSON字符串生成对象实体
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="json">json字符串(eg.{"ID":"112","Name":"石子儿"})</param>
/// <returns>对象实体</returns>
public static T DeserializeJsonToObject<T>(string json) where T : class
{
JsonSerializer serializer = new JsonSerializer();
StringReader sr = new StringReader(json);
object o = serializer.Deserialize(new JsonTextReader(sr), typeof(T));
T t = o as T;
return t;
}
/// <summary>
/// 解析JSON数组生成对象实体集合
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="json">json数组字符串(eg.[{"ID":"112","Name":"石子儿"}])</param>
/// <returns>对象实体集合</returns>
public static List<T> DeserializeJsonToList<T>(string json) where T : class
{
JsonSerializer serializer = new JsonSerializer();
StringReader sr = new StringReader(json);
object o = serializer.Deserialize(new JsonTextReader(sr), typeof(List<T>));
List<T> list = o as List<T>;
return list;
}
/// <summary>
/// 反序列化JSON到给定的匿名对象.
/// </summary>
/// <typeparam name="T">匿名对象类型</typeparam>
/// <param name="json">json字符串</param>
/// <param name="anonymousTypeObject">匿名对象</param>
/// <returns>匿名对象</returns>
public static T DeserializeAnonymousType<T>(string json, T anonymousTypeObject)
{
T t = JsonConvert.DeserializeAnonymousType(json, anonymousTypeObject);
return t;
}
}
///// <summary>
///// 与服务器通信用对象
///// </summary>
//public class Operation
//{
// private string _cid = "";
// public string cid
// {
// get { return _cid; }
// set { _cid = value; }
// }
// public int seq { get; set; }
// public int op { get; set; }
// public int status { get; set; }
// private string _error = "";
// public string error
// {
// get { return _error; }
// set { _error = value; }
// }
// private Dictionary<string, string> _data = new Dictionary<string,string>();
// public Dictionary<string, string> data {
// get { return _data; }
// set { _data = value; }
// }
//}
}
using log4net;
using System;
using System.Reflection;
using System.Drawing;
using log4net.Repository;
using log4net.Config;
using System.IO;
using System.Text;
using System.Collections.Generic;
namespace DL.Utils
{
public class LogUtil
{
static Dictionary<string, ILog> LogMap = new Dictionary<string, ILog>();
public delegate void ShowMsg(string msg);
public static event ShowMsg ShowDebug;
public static event ShowMsg ShowInfo;
public static event ShowMsg ShowWarn;
public static event ShowMsg ShowError;
static readonly ILog defaultLog = LogManager.GetLogger("AIOBOX");
public static void Init()
{
XmlConfigurator.Configure(new FileInfo("log4net.config"));
LogMap.Add("AIOBOX", defaultLog);
}
public static void AddLogMap(string key, ILog log)
{
LogMap.Add(key, log);
}
#region Main log
public static void Debug(string msg, ILog log = null)
{
ShowDebug?.Invoke(msg);
if (log == null)
defaultLog.Debug(msg);
else
log.Debug(msg);
}
public static void Info(string msg, ILog log = null)
{
ShowInfo?.Invoke(msg);
if (log == null)
defaultLog.Info(msg);
else
log.Info(msg);
}
public static void Info(string msg, string logName)
{
ShowInfo?.Invoke(msg);
if (string.IsNullOrEmpty(logName))
defaultLog.Info(msg);
else if (LogMap.ContainsKey(logName) && LogMap[logName] != null)
LogMap[logName].Info(msg);
}
public static void Warn(string msg, ILog log = null)
{
ShowWarn?.Invoke(msg);
if (log == null)
defaultLog.Warn(msg);
else
log.Warn(msg);
}
public static void Error(string msg, Exception exception, ILog log)
{
StringBuilder sb = new StringBuilder(msg + "\r\n");
if (log == null)
{
if (exception == null)
defaultLog.Error(msg);
else
{
defaultLog.Error(msg, exception);
sb.Append(exception.StackTrace);
}
}
else
{
if (exception == null)
log.Error(msg);
else
{
log.Error(msg, exception);
sb.Append(exception.StackTrace);
}
}
ShowError?.Invoke(sb.ToString());
}
public static void Error(string msg, ILog log, Exception exception)
{
StringBuilder sb = new StringBuilder(msg + "\r\n");
if (log == null)
{
if (exception == null)
defaultLog.Error(msg);
else
{
defaultLog.Error(msg, exception);
sb.Append(exception.StackTrace);
}
}
else
{
if (exception == null)
log.Error(msg);
else
{
log.Error(msg, exception);
sb.Append(exception.StackTrace);
}
}
ShowError?.Invoke(sb.ToString());
}
public static void Error(string msg, ILog log)
{
StringBuilder sb = new StringBuilder(msg + "\r\n");
if (log == null)
{
defaultLog.Error(msg);
}
else
{
log.Error(msg);
}
ShowError?.Invoke(sb.ToString());
}
public static void Error(string msg, Exception exception)
{
StringBuilder sb = new StringBuilder(msg + "\r\n");
if (exception == null)
defaultLog.Error(msg);
else
{
defaultLog.Error(msg, exception);
sb.Append(exception.StackTrace);
}
ShowError?.Invoke(sb.ToString());
}
public static void Error(string msg)
{
defaultLog.Error(msg);
ShowError?.Invoke(msg);
}
#endregion
}
}
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("DL.IOModule")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DL.IOModule")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("f85a7412-b5b3-4291-a448-a10564602e1a")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DL.Com.Protocol.Modbus
{
/// <summary>
/// 线圈寄存器:可读可写。
/// 支持的功能码:
/// 0x01:读线圈
/// 0x05:写线圈
/// 0x0F:写多个线圈
/// </summary>
public class CoilRegister : Register
{
public CoilRegister() : base()
{
FunctionCodes.Add(RegisterFunction.Read, 0x01);
FunctionCodes.Add(RegisterFunction.WriteSingle, 0x05);
FunctionCodes.Add(RegisterFunction.WriteMultiple, 0x0F);
}
/// <summary>
/// PLC地址
/// </summary>
public new string PLCAddress
{
get { return $"0{FrameStruct.PDU.Data.Addr.GetIntValue()}"; }
}
/// <summary>
/// 解析写单个线圈
/// </summary>
/// <returns>写入成功</returns>
protected override bool ParseWriteSingle(byte[] respoonse)
{
if (GetResponseResult(respoonse, out byte[] data))
{
//数据部分,发送与接收一致
byte[] senddata = FrameStruct.PDU.Data.ToBytes();
if (data != null && data.Length != senddata.Length)
return false;
for (int i = 0; i < senddata.Length; i++)
{
if (senddata[i] != data[i])
{
return false;
}
}
return true;
}
return false;
}
/// <summary>
/// 解析写多个线圈
/// </summary>
/// <returns>写入成功/returns>
protected override bool ParseWriteMultiple(byte[] response)
{
if (GetResponseResult(response, out byte[] data))
{
byte[] senddata = FrameStruct.PDU.Data.AddrValueToBytes();
if (data != null && data.Length != senddata.Length)
return false;
for (int i = 0; i < senddata.Length; i++)
{
if (senddata[i] != data[i])
{
return false;
}
}
return true;
}
return false;
}
protected override void SetParamPDU(CmdByte cmd)
{
if (cmd.Function.Equals(RegisterFunction.WriteSingle))
{
SetPDU(cmd.Function, cmd.StartAddr, cmd.Count.Equals(new Byte2 { ByteH = 0x00, ByteL = 0x00 }) ? cmd.Count : new Byte2 { ByteH = 0xFF, ByteL = 0x00 }, cmd.ByteLength, cmd.ValuesOfMultiple);
}
else if (cmd.Function.Equals(RegisterFunction.WriteMultiple))
{
SetPDU(cmd.Function, cmd.StartAddr, cmd.Count, cmd.ByteLength, cmd.ValuesOfMultiple);
}
else
{
SetPDU(RegisterFunction.Read, cmd.StartAddr, cmd.Count);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DL.Com.Protocol.Modbus
{
/// <summary>
/// 数据帧:报文头+帧结构
/// </summary>
public class DataFrame
{
/// <summary>
/// 报文头
/// </summary>
public MBAP MBAP;
/// <summary>
/// 帧结构
/// </summary>
public PDU PDU;
public DataFrame()
{
MBAP = new MBAP();
PDU = new PDU();
}
/// <summary>
/// 设置帧数据
/// </summary>
/// <param name="functionCode">功能码</param>
/// <param name="addr">开始地址</param>
/// <param name="value">数量</param>
/// <param name="bytelenght">字节长度,写多个线圈/寄存器使用</param>
/// <param name="valueofmulti">写入的值,写多个线圈/寄存器使用</param>
public void SetPDU(byte functionCode, ushort addr, ushort value, byte bytelenght = 0, byte[] valueofmulti = null)
{
PDU.SetPDUFunctionCode(functionCode);
PDU.SetPDUData(addr, value, bytelenght, valueofmulti);
MBAP.SetDataLength(PDU.GetLength());
}
/// <summary>
/// 设置帧数据
/// </summary>
/// <param name="functionCode">功能码</param>
/// <param name="addr">开始地址</param>
/// <param name="value">数量</param>
/// <param name="bytelenght">字节长度,写多个线圈/寄存器使用</param>
/// <param name="valueofmulti">写入的值,写多个线圈/寄存器使用</param>
public void SetPDU(byte functionCode, Byte2 addr, Byte2 value, byte bytelenght = 0x00, byte[] valueofmulti = null)
{
PDU.SetPDUFunctionCode(functionCode);
PDU.SetPDUData(addr, value, bytelenght, valueofmulti);
MBAP.SetDataLength(PDU.GetLength());
}
/// <summary>
/// 设置报文头
/// </summary>
public void SetMBAP(ushort serialnum, byte equipAddr, ushort protocolid = 0)
{
MBAP.SetSerialNum(serialnum);
MBAP.SetEquipAddr(equipAddr);
MBAP.SetProtocolId(protocolid);
}
/// <summary>
/// 设置报文头
/// </summary>
public void SetMBAP(Byte2 serialnum, byte equipAddr, ushort protocolid = 0)
{
MBAP.SetSerialNum(serialnum);
MBAP.SetEquipAddr(equipAddr);
MBAP.SetProtocolId(protocolid);
}
/// <summary>
/// 数据帧字节数据
/// </summary>
/// <returns></returns>
public byte[] ToBytes()
{
List<byte> tmp = new List<byte>();
tmp.AddRange(MBAP.ToBytes());
tmp.AddRange(PDU.ToBytes());
return tmp.ToArray();
}
public byte[] ToMbapFuncCodeBytes()
{
List<byte> tmp = new List<byte>();
tmp.AddRange(MBAP.ToBytes());
tmp.Add(PDU.FuncCode);
return tmp.ToArray();
}
}
/// <summary>
/// 报文头
/// </summary>
public class MBAP
{
/// <summary>
/// 报文序列号,事务处理标识符
/// 长度:2字节
/// </summary>
public Byte2 SerialNum;
/// <summary>
/// 协议标识符
/// 0000标识ModbusTCP协议
/// 长度:2字节
/// </summary>
public Byte2 ProtocolId;
/// <summary>
/// 接下来的数据长度
/// 长度:2字节
/// </summary>
public Byte2 DataLength;
/// <summary>
/// 设备地址
/// 长度:1字节
/// </summary>
public byte EquipAddr;
public MBAP()
{
SerialNum = new Byte2();
ProtocolId = new Byte2();
DataLength = new Byte2();
}
public void SetData(byte[] data)
{
if (data.Length > 7)
{
SerialNum.Set(data[0], data[1]);
ProtocolId.Set(data[2], data[3]);
DataLength.Set(data[4], data[5]);
EquipAddr = data[6];
}
}
public void SetSerialNum(UInt16 serialnum)
{
SerialNum.SetByInt(serialnum);
}
public void SetSerialNum(byte Hi, byte Low)
{
SerialNum.Set(Hi, Low);
}
public void SetSerialNum(Byte2 stru2Byte)
{
SerialNum.Set(stru2Byte);
}
/// <summary>
/// 设置协议ID,默认TCP协议
/// </summary>
/// <param name="protocolid"></param>
public void SetProtocolId(UInt16 protocolid = 0)
{
ProtocolId.SetByInt(protocolid);
}
/// <summary>
/// 设置协议ID,默认TCP协议
/// </summary>
/// <param name="Hi"></param>
/// <param name="Low"></param>
public void SetProtocolId(byte Hi = 0x00, byte Low = 0x00)
{
ProtocolId.Set(Hi, Low);
}
public void SetProtocolId(Byte2 stru2Byte)
{
ProtocolId.Set(stru2Byte);
}
/// <summary>
/// 设置协议地址
/// </summary>
/// <param name="equipAddr"></param>
public void SetEquipAddr(byte equipAddr)
{
EquipAddr = equipAddr;
}
/// <summary>
/// 设置接下来的数据长度
/// </summary>
/// <param name="datalength">PDU里的数据长度</param>
public void SetDataLength(ushort datalength)
{
DataLength.SetByInt((ushort)(datalength+1));
}
/// <summary>
/// 设置接下来的数据长度
/// </summary>
/// <param name="Hi"></param>
/// <param name="Low"></param>
public void SetDataLength(byte Hi, byte Low)
{
DataLength.Set(Hi, Low);
}
public override bool Equals(object obj)
{
MBAP cMBAP = obj as MBAP;
if (cMBAP == null)
return false;
if (cMBAP.SerialNum.Equals(this.SerialNum) &&
cMBAP.ProtocolId.Equals(this.ProtocolId) &&
cMBAP.EquipAddr.Equals(this.EquipAddr))
return true;
else
return false;
}
/// <summary>
/// 报文头字节数据
/// </summary>
/// <returns></returns>
public byte[] ToBytes()
{
List<byte> tmp = new List<byte>();
tmp.AddRange(SerialNum.ToBytes());
tmp.AddRange(ProtocolId.ToBytes());
tmp.AddRange(DataLength.ToBytes());
tmp.Add(EquipAddr);
return tmp.ToArray();
}
}
/// <summary>
/// 数据帧
/// </summary>
public class PDU
{
/// <summary>
/// 功能码
/// </summary>
public byte FuncCode;
/// <summary>
/// 数据
/// </summary>
public DataInPDU Data;
public PDU()
{
Data = new DataInPDU();
}
/// <summary>
/// 设置帧结构功能码
/// </summary>
/// <param name="funcCode">功能码</param>
public void SetPDUFunctionCode(byte funcCode)
{
FuncCode = funcCode;
}
public void SetPDUData(ushort addr, ushort value, byte bytelenght = 0, byte[] valueofmulti = null)
{
Data.SetData(addr, value, bytelenght, valueofmulti);
}
public void SetPDUData(Byte2 addr, Byte2 value, byte bytelenght = 0x00, byte[] valueofmulti = null)
{
Data.SetData(addr, value, bytelenght, valueofmulti);
}
/// <summary>
/// 帧结构的数据长度
/// </summary>
/// <returns></returns>
public ushort GetLength()
{
return (ushort)(Data.Length() + 1);
}
public byte[] ToBytes()
{
List<byte> tmp = new List<byte>();
tmp.Add(FuncCode);
tmp.AddRange(Data.ToBytes());
return tmp.ToArray();
}
}
public class DataInPDU
{
/// <summary>
/// 起始地址/寄存器地址
/// </summary>
public Byte2 Addr;
/// <summary>
/// 数量/值
/// </summary>
public Byte2 Value;
/// <summary>
/// 字节长度,写多个线圈/保持寄存器时使用
/// </summary>
public byte ByteLength;
/// <summary>
/// 输出值/寄存器值,写多个线圈/保持寄存器时使用
/// </summary>
public List<byte> ValueOfMulti;
public DataInPDU()
{
Addr = new Byte2();
Value = new Byte2();
ValueOfMulti = new List<byte>();
}
public void SetData(ushort addr, ushort value, byte bytelenght = 0, byte[] valueofmulti = null)
{
Addr.SetByInt(addr);
Value.SetByInt(value);
ByteLength = bytelenght;
ValueOfMulti.Clear();
if (valueofmulti != null)
foreach (var item in valueofmulti)
{
ValueOfMulti.Add(item);
}
}
public void SetData(Byte2 addr, Byte2 value, byte bytelenght = 0x00, byte[] valueofmulti = null)
{
Addr.Set(addr);
Value.Set(value);
ByteLength = bytelenght;
ValueOfMulti.Clear();
if (valueofmulti != null)
foreach (var item in valueofmulti)
{
ValueOfMulti.Add(item);
}
}
public byte[] ToBytes()
{
List<byte> tmp = new List<byte>();
tmp.AddRange(Addr.ToBytes());
tmp.AddRange(Value.ToBytes());
if (ByteLength != 0)
{
tmp.Add(ByteLength);
foreach (var item in ValueOfMulti)
{
tmp.Add(item);
}
}
return tmp.ToArray();
}
public byte[] AddrValueToBytes()
{
List<byte> tmp = new List<byte>();
tmp.AddRange(Addr.ToBytes());
tmp.AddRange(Value.ToBytes());
return tmp.ToArray();
}
public int Length()
{
List<byte> tmp = new List<byte>();
tmp.AddRange(Addr.ToBytes());
tmp.AddRange(Value.ToBytes());
if (ByteLength != 0)
{
tmp.Add(ByteLength);
foreach (var item in ValueOfMulti)
{
tmp.Add(item);
}
}
return tmp.Count;
}
}
/// <summary>
/// 两字节组成的值
/// </summary>
public struct Byte2
{
public byte ByteH { get; set; }
public byte ByteL { get; set; }
public static Byte2 GetStru2Byte(ushort val)
{
return new Byte2
{
ByteH = (byte)((val >> 8) & 0xff),
ByteL = (byte)((val & 0xff))
};
}
public static ushort GetUInt16(byte H,byte L)
{
return (ushort)(((H & 0xff) << 8) | (L & 0xff));
}
public static short GetInt16(byte H, byte L)
{
return (short)((H << 8) | (L & 0xff));
}
public static int GetInt32(byte H, byte L)
{
return ((H << 8) | (L & 0xff));
}
public static uint GetUInt32(byte H, byte L)
{
return (uint)(((H & 0xff) << 8) | (L & 0xff));
}
public void SetByInt(ushort val)
{
ByteH = (byte)((val >> 8) & 0xff);
ByteL = (byte)((val & 0xff));
}
public void Set(byte High, byte Low)
{
ByteH = High;
ByteL = Low;
}
public void Set(Byte2 stru2Byte)
{
ByteH = stru2Byte.ByteH;
ByteL = stru2Byte.ByteL;
}
public ushort GetIntValue()
{
return (ushort)(((ByteH & 0xff) << 8) | (ByteL & 0xff));
}
public override string ToString()
{
return $"{ByteH.ToString("x2")} {ByteL.ToString("x2")}";
}
public override bool Equals(object obj)
{
Byte2 stru2Byte = (Byte2)obj;
return ByteH.Equals(stru2Byte.ByteH) && ByteL.Equals(stru2Byte.ByteL);
}
public byte[] ToBytes()
{
return new byte[] { ByteH, ByteL };
}
}
/// <summary>
/// 四字节组成的值
/// </summary>
public struct Byte4
{
public byte ByteH1 { get; set; }
public byte ByteH2 { get; set; }
public byte ByteL1 { get; set; }
public byte ByteL2 { get; set; }
public static Byte4 GetStru2Byte(int val)
{
return new Byte4
{
ByteH1 = (byte)((val >> 24) & 0xff),
ByteH2 = (byte)((val >> 16) & 0xff),
ByteL1 = (byte)((val >> 8) & 0xff),
ByteL2 = (byte)((val & 0xff))
};
}
public void SetByInt(uint val)
{
ByteH1 = (byte)((val >> 24) & 0xff);
ByteH2 = (byte)((val >> 16) & 0xff);
ByteL1 = (byte)((val >> 8) & 0xff);
ByteL2 = (byte)((val & 0xff));
}
public void Set(Byte4 stru4Byte)
{
ByteH1 = stru4Byte.ByteH1;
ByteH2 = stru4Byte.ByteH2;
ByteL1 = stru4Byte.ByteL1;
ByteL2 = stru4Byte.ByteL2;
}
public static uint GetUInt32(byte h1,byte h2,byte l1,byte l2)
{
return (uint)(((h1 & 0xff) << 24) | ((h2 & 0xff) << 16) | ((l1 & 0xff) << 8) | (l2 & 0xff));
}
public static int GetInt32(byte h1, byte h2, byte l1, byte l2)
{
return (int)((h1 << 24) | ((h2 & 0xff) << 16) | ((l1 & 0xff) << 8) | (l2 & 0xff));
}
/// <summary>
/// 大终端转float
/// </summary>
/// <param name="h1"></param>
/// <param name="h2"></param>
/// <param name="l1"></param>
/// <param name="l2"></param>
/// <returns></returns>
public static float GetFloat(byte h1, byte h2, byte l1, byte l2)
{
byte[] tmp = new byte[4] { h1,h2,l1,l2};
return (float)(GetInt32(h1, h2, l1, l2));
//float f = 0;
//byte[] x = tmp;
//byte i;
//unsafe
//{
// void* pf;
// fixed(byte* pb = x)
// {
// pf = &f;
// for (i = 0; i < tmp.Length; i++)
// {
// *((byte*)pf + i) = *(pb+i);
// }
// }
//}
//return f;
}
public uint GetIntValue()
{
return (uint)(((ByteH1 & 0xff) << 24) | ((ByteH2 & 0xff) << 16) | ((ByteL1 & 0xff) << 8) | (ByteL2 & 0xff));
}
public override string ToString()
{
return $"{ByteH1.ToString("x2")} {ByteH2.ToString("x2")} {ByteL1.ToString("x2")} {ByteL2.ToString("x2")}";
}
public override bool Equals(object obj)
{
Byte4 stru4Byte = (Byte4)obj;
return ByteH1.Equals(stru4Byte.ByteH1) && ByteH2.Equals(stru4Byte.ByteH2) && ByteL1.Equals(stru4Byte.ByteL1) && ByteL2.Equals(stru4Byte.ByteL2);
}
public byte[] ToBytes()
{
return new byte[] { ByteH1, ByteH2, ByteL1, ByteL2 };
}
}
public class ResponseData
{
public MBAP MBAP { get; set; }
public byte FuncCode { get; set; }
public byte[] OtherData { get; set; }
public ResponseData()
{
MBAP = new MBAP();
}
public void Set(byte[] data)
{
if (data == null)
return;
MBAP.SetData(data);
FuncCode = data[7];
OtherData = new byte[data.Length - 8];
Array.Copy(data, 8, OtherData, 0, data.Length - 8);
}
public byte[] ToBytes()
{
List<byte> vs = new List<byte>();
vs.AddRange(MBAP.ToBytes());
vs.Add(FuncCode);
vs.AddRange(OtherData);
return vs.ToArray();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DL.Com.Protocol.Modbus
{
/// <summary>
/// 离散输入寄存器
/// 功能码0x02
/// </summary>
public class DiscreteInputRegister:Register
{
/// <summary>
/// 离散输入寄存器
/// 功能码0x02
/// </summary>
public DiscreteInputRegister() :base()
{
FunctionCodes.Add(RegisterFunction.Read, 0x02);
}
/// <summary>
/// PLC地址
/// </summary>
public new string PLCAddress
{
get { return $"1{FrameStruct.PDU.Data.Addr.GetIntValue()}"; }
}
protected override bool ParseWriteMultiple(byte[] response)
{
throw new NotImplementedException();
}
protected override bool ParseWriteSingle(byte[] response)
{
throw new NotImplementedException();
}
protected override void SetParamPDU(CmdByte cmdByte)
{
SetPDU(RegisterFunction.Read, cmdByte.StartAddr, cmdByte.Count);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DL.Com.Protocol.Modbus
{
/// <summary>
/// 保持寄存器
/// 0x03
/// </summary>
public class HoldingRegister : Register
{
public HoldingRegister() : base()
{
FunctionCodes.Add(RegisterFunction.Read, 0x03);
FunctionCodes.Add(RegisterFunction.WriteSingle, 0x06);
FunctionCodes.Add(RegisterFunction.WriteMultiple, 0x10);
}
/// <summary>
/// PLC地址
/// </summary>
public new string PLCAddress
{
get { return $"4{FrameStruct.PDU.Data.Addr.GetIntValue()}"; }
}
public override byte[] GetRequestBytes(RegisterFunction func, ushort startAddr, ushort countOrValue,byte equipAddr=1, ushort[] ValuesOfMultiple = null)
{
CmdByte cmdByte = new CmdByte();
cmdByte.StartAddr = Byte2.GetStru2Byte(startAddr);
cmdByte.Function = func;
cmdByte.Count = Byte2.GetStru2Byte(countOrValue);
if (func.Equals(RegisterFunction.WriteMultiple))
{
if (ValuesOfMultiple == null)
return null;
List<byte> values = new List<byte>();
foreach (var item in ValuesOfMultiple)
{
values.AddRange(Byte2.GetStru2Byte(item).ToBytes());
}
cmdByte.ByteLength = (byte)(countOrValue * 2);
cmdByte.ValuesOfMultiple = values.ToArray();
}
SetMBAP(_serialnum, equipAddr);
SetParamPDU(cmdByte);
return DataFrame;
}
protected override void SetParamPDU(CmdByte cmdByte)
{
if (cmdByte.Function.Equals(RegisterFunction.WriteSingle))
{
SetPDU(cmdByte.Function, cmdByte.StartAddr, cmdByte.Count, cmdByte.ByteLength, cmdByte.ValuesOfMultiple);
}
else if (cmdByte.Function.Equals(RegisterFunction.WriteMultiple))
{
SetPDU(cmdByte.Function, cmdByte.StartAddr, cmdByte.Count, cmdByte.ByteLength, cmdByte.ValuesOfMultiple);
}
else
SetPDU(RegisterFunction.Read, cmdByte.StartAddr, cmdByte.Count);
}
protected override bool ParseWriteSingle(byte[] response)
{
if (GetResponseResult(response, out byte[] data))
{
//数据部分,发送与接收一致
byte[] senddata = FrameStruct.PDU.Data.ToBytes();
if (data != null && data.Length != senddata.Length)
return false;
for (int i = 0; i < senddata.Length; i++)
{
if (senddata[i] != data[i])
{
return false;
}
}
return true;
}
return false;
}
protected override bool ParseWriteMultiple(byte[] response)
{
if (GetResponseResult(response, out byte[] data))
{
byte[] senddata = FrameStruct.PDU.Data.AddrValueToBytes();
if (data != null && data.Length != senddata.Length)
return false;
for (int i = 0; i < senddata.Length; i++)
{
if (senddata[i] != data[i])
{
return false;
}
}
return true;
}
return false;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DL.Com.Protocol.Modbus
{
/// <summary>
/// 输入寄存器
/// 支持的功能码0x04
/// </summary>
public class InputRegister : Register
{
public InputRegister() : base()
{
FunctionCodes.Add(RegisterFunction.Read, 0x04);
}
/// <summary>
/// PLC地址
/// </summary>
public new string PLCAddress
{
get { return $"3{FrameStruct.PDU.Data.Addr.GetIntValue()}"; }
}
protected override bool ParseWriteMultiple(byte[] response)
{
throw new NotImplementedException();
}
protected override bool ParseWriteSingle(byte[] response)
{
throw new NotImplementedException();
}
protected override void SetParamPDU(CmdByte cmdByte)
{
SetPDU(RegisterFunction.Read, cmdByte.StartAddr, cmdByte.Count);
}
}
}
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using DL.Com;
using DL.Utils;
namespace DL.Com.Protocol.Modbus
{
/// <summary>
/// 寄存器
/// </summary>
public abstract class Register
{
public delegate void StatusChangedEventHandler(StatusChangedEventArgs statusChangedEventArgs);
public event StatusChangedEventHandler StatusChanged;
protected static log4net.ILog log;
protected static ushort _serialnum = 0;
public Register(string logname = "logModbus")
{
log = log4net.LogManager.GetLogger(logname);
FunctionCodes = new Dictionary<RegisterFunction, byte>();
FrameStruct = new DataFrame();
}
/// <summary>
/// 功能码
/// </summary>
public Dictionary<RegisterFunction, byte> FunctionCodes { get; set; }
/// <summary>
/// 帧结构
/// </summary>
public DataFrame FrameStruct { get; protected set; }
/// <summary>
/// 数据帧--字节数据
/// </summary>
public byte[] DataFrame { get { return FrameStruct.ToBytes(); } }
/// <summary>
/// PLC地址
/// </summary>
public string PLCAddress { get; }
/// <summary>
/// 根据命令设置PDU参数
/// </summary>
/// <param name="cmdByte"></param>
/// <returns></returns>
protected abstract void SetParamPDU(CmdByte cmdByte);
/// <summary>
/// 设置MBAP报文头
/// </summary>
/// <param name="serialnum">事务处理标识,即报文序列号</param>
/// <param name="equipAddr">单元标识符,即设备地址</param>
protected void SetMBAP(ushort serialnum, byte equipAddr)
{
FrameStruct.SetMBAP(serialnum, equipAddr);
_serialnum++;
if (_serialnum >= ushort.MaxValue)
{
_serialnum = 0;
}
}
/// <summary>
/// 设置帧结构
/// </summary>
/// <param name="funcStr">功能</param>
/// <param name="addr">开始地址</param>
/// <param name="value">数量/值</param>
/// <param name="bytelenght">字节长度,写多个线圈/寄存器使用</param>
/// <param name="valueofmulti">写入的值,写多个线圈/寄存器使用</param>
protected void SetPDU(RegisterFunction func, Byte2 addr, Byte2 value, byte bytelenght = 0x00, byte[] valueofmulti = null)
{
FrameStruct.SetPDU(FunctionCodes[func], addr, value, bytelenght, valueofmulti);
}
/// <summary>
/// 检查响应的MBAP+功能码是否与请求一致
/// </summary>
/// <param name="data">响应的数据</param>
/// <returns>true:请求与返回对应</returns>
private bool CheckResponse(byte[] data, bool ignoreSerialNum = false)
{
if (data != null && data.Length > 8)
{
if (FrameStruct.MBAP.SerialNum.ByteH.Equals(data[0]) &&
FrameStruct.MBAP.SerialNum.ByteL.Equals(data[1]) &&
FrameStruct.MBAP.ProtocolId.ByteH.Equals(data[2]) &&
FrameStruct.MBAP.ProtocolId.ByteL.Equals(data[3]) &&
FrameStruct.MBAP.EquipAddr.Equals(data[6]) &&
FrameStruct.PDU.FuncCode.Equals(data[7])
)
{
return true;
}
if (ignoreSerialNum)
{
if (
FrameStruct.MBAP.ProtocolId.ByteH.Equals(data[2]) &&
FrameStruct.MBAP.ProtocolId.ByteL.Equals(data[3]) &&
FrameStruct.MBAP.EquipAddr.Equals(data[6]) &&
FrameStruct.PDU.FuncCode.Equals(data[7])
)
{
return true;
}
}
}
return false;
}
/// <summary>
/// 获取响应数据的结果,并返回响应的
/// </summary>
/// <param name="data">响应的数据</param>
/// <returns>true:响应成功</returns>
protected bool GetResponseResult(byte[] response, out byte[] data, bool ignoreSerial = false)
{
if (CheckResponse(response, ignoreSerial))
{
data = new byte[response.Length - 8];
Array.Copy(response, 8, data, 0, response.Length - 8);
return true;
}
if (response != null && response.Length >= 8)
{
data = new byte[] { response[7] };
if ((data[0] & 0x80) == 0x80)
{
LogUtil.Error($"从站异常响应[{StringHelper.ToHexString(data[0])}],响应数据为[{StringHelper.ToHexString(response)}]", log);
}
return false;
}
data = new byte[] { 0x00 };
return false;
}
/// <summary>
/// 解析读操作的响应数据
/// </summary>
/// <param name="response">响应的字节数据</param>
/// <param name="data"></param>
/// <param name="ignoreserial">忽略请求编号</param>
/// <returns>true:读取成功</returns>
protected virtual bool ParseRead(byte[] response, out byte[] data, bool ignoreserial = false)
{
data = null;
if (GetResponseResult(response, out byte[] data1, ignoreserial))
{
int len = data1[0];
data = new byte[len];
Array.Copy(data1, 1, data, 0, len);
return true;
}
return false;
}
/// <summary>
/// 解析写单个操作的响应数据
/// </summary>
/// <param name="response">响应的字节数据</param>
/// <returns>true:写入单个操作成功</returns>
protected abstract bool ParseWriteSingle(byte[] response);
/// <summary>
/// 解析写多个操作的响应数据
/// </summary>
/// <param name="response">响应的字节数据</param>
/// <returns>true:写多单个操作成功</returns>
protected abstract bool ParseWriteMultiple(byte[] response);
/// <summary>
/// 获取响应的结果
/// </summary>
/// <param name="function"></param>
/// <param name="response"></param>
/// <param name="data"></param>
/// <returns>解析</returns>
public bool GetResult(RegisterFunction function, byte[] response, out byte[] data)
{
bool rtn = false;
data = null;
switch (function)
{
case RegisterFunction.Read:
rtn = ParseRead(response, out data);
break;
case RegisterFunction.WriteSingle:
rtn = ParseWriteSingle(response);
break;
case RegisterFunction.WriteMultiple:
rtn = ParseWriteMultiple(response);
break;
default:
rtn = ParseRead(response, out data);
break;
}
return rtn;
}
public bool GetReadReault(byte[] response, out byte[] data)
{
bool rtn = ParseRead(response, out data, true);
return rtn;
}
/// <summary>
/// 分离多个反馈字节
/// </summary>
/// <param name="data"></param>
/// <returns>《功能码,响应的数据》</returns>
public static List<byte[]> SplitResponse(byte[] data)
{
List<byte[]> rtn = new List<byte[]>();
List<byte> tmpdata = new List<byte>();
tmpdata.AddRange(data);
while (tmpdata.Count >= 8)
{
if (ParseHeader(tmpdata.ToArray(), out byte func, out int len))
{
byte[] tmp = new byte[len + 6];
Array.Copy(tmpdata.ToArray(), 0, tmp, 0, len + 6);
rtn.Add(tmp);
tmpdata.RemoveRange(0, tmp.Length);
}
}
return rtn;
}
/// <summary>
/// 解析头
/// </summary>
/// <param name="header"></param>
/// <param name="func">功能码</param>
/// <param name="len">长度</param>
/// <returns>解析成功</returns>
public static bool ParseHeader(byte[] header, out byte func, out int len)
{
func = 0;
len = 0;
if (header != null && header.Length >= 8)
{
func = header[7];
len = Byte2.GetInt32(header[4], header[5]);
return true;
}
return false;
}
/// <summary>
/// 写入多个值时,将写入的值转换为发送的数组
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static int[] GetValuesWithMultiMode(int[] data)
{
int mod = data.Length % 8;
List<int> tmp = new List<int>();
int t = 0;
for (int i = 0; i < data.Length; i++)
{
if ((i + 1) % 8 == 0)
{
t += data[i] * (int)Math.Pow(2, data[i]);
tmp.Add(t);
t = 0;
}
else
{
t += data[i] * (int)Math.Pow(2, data[i]);
}
}
if (mod != 0)
tmp.Add(t);
return tmp.ToArray();
}
/// <summary>
/// 设置并获取请求字节数组
/// </summary>
/// <param name="func"></param>
/// <param name="startAddr"></param>
/// <param name="countOrValue"></param>
/// <param name="ValuesOfMultiple"></param>
/// <returns></returns>
public virtual byte[] GetRequestBytes(RegisterFunction func, ushort startAddr, ushort countOrValue, byte equipAddr = 1, ushort[] ValuesOfMultiple = null)
{
CmdByte cmdByte = new CmdByte();
cmdByte.StartAddr = Byte2.GetStru2Byte(startAddr);
cmdByte.Function = func;
cmdByte.Count = Byte2.GetStru2Byte(countOrValue);
if (func.Equals(RegisterFunction.WriteMultiple))
{
if (ValuesOfMultiple == null)
return null;
List<byte> values = new List<byte>();
foreach (var item in ValuesOfMultiple)
{
values.Add((byte)item);
}
cmdByte.ByteLength = (byte)(countOrValue % 8 == 0 ? countOrValue / 8 : countOrValue / 8 + 1);
cmdByte.ValuesOfMultiple = values.ToArray();
}
SetMBAP(_serialnum, equipAddr);
SetParamPDU(cmdByte);
return DataFrame;
}
}
public class StatusChangedEventArgs : EventArgs
{
public Dictionary<int, byte> ChangedIdxAndValue { get; set; }
public byte[] Data;
public bool Init { get; set; }
public StatusChangedEventArgs()
{
ChangedIdxAndValue = new Dictionary<int, byte>();
}
}
public class CmdByte
{
public RegisterFunction Function { get; set; }
public Byte2 StartAddr { get; set; }
public Byte2 Count { get; set; }
public byte ByteLength { get; set; }
public byte[] ValuesOfMultiple { get; set; }
string ToHexString(byte[] data)
{
if (data == null)
return "";
StringBuilder stringBuilder = new StringBuilder();
foreach (var item in data)
{
stringBuilder.Append(item.ToString("x2"));
stringBuilder.Append(" ");
}
return stringBuilder.ToString().Trim();
}
public override string ToString()
{
return $"[Function={Function.ToString()},StartAddr={StartAddr},Count/Value={Count},ByteLength={ByteLength},ValuesOfMultiple={ToHexString(ValuesOfMultiple)}]";
}
}
/// <summary>
/// 寄存器功能
/// </summary>
public enum RegisterFunction
{
/// <summary>
/// 读
/// </summary>
Read,
/// <summary>
/// 写单个
/// </summary>
WriteSingle,
/// <summary>
/// 写多个
/// </summary>
WriteMultiple,
}
/// <summary>
/// 寄存器类型
/// </summary>
public enum RegisterType
{
/// <summary>
/// 线圈,支持的功能码为 0x01,0x05,0x0f
/// </summary>
CoilSatus,
/// <summary>
/// 离散输入,支持的功能码为 0x02
/// </summary>
InputStatus,
/// <summary>
/// 输入寄存器,支持的功能码为 0x04
/// </summary>
InputRegister,
/// <summary>
/// 保持寄存器,支持的功能码为 0x03,0x06,0x10
/// </summary>
HoldingRegister,
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DL.Utils
{
public class StringHelper
{
/// <summary>
/// 字节转十六进制字符串
/// </summary>
/// <param name="buff"></param>
/// <returns></returns>
public static string ToHexString(byte[] buff)
{
StringBuilder sb = new StringBuilder("");
if (buff == null || buff.Length<1) return sb.ToString();
for (int i = 0; i < buff.Length; i++)
{
sb.Append(buff[i].ToString("X2"));
sb.Append(" ");
}
sb.Remove(sb.Length - 1, 1);
return sb.ToString();
}
public static string ToBinaryString(byte[] data)
{
StringBuilder stringBuilder = new StringBuilder("");
if (data == null || data.Length < 1) return stringBuilder.ToString();
stringBuilder.Append("【");
foreach (var item in data)
{
stringBuilder.Append(Convert.ToString(item, 2).PadLeft(8, '0'));
stringBuilder.Append(" ");
}
stringBuilder.Remove(stringBuilder.Length - 1, 1);
stringBuilder.Append("】");
return stringBuilder.ToString();
}
public static string ToHexString(byte data)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("【");
stringBuilder.Append(data.ToString("x2"));
stringBuilder.Append("】");
return stringBuilder.ToString();
}
public static byte[] StrToHexByte(string hexString)
{
hexString = hexString.Replace(" ", "");
if ((hexString.Length % 2) != 0)
hexString += " ";
byte[] returnBytes = new byte[hexString.Length / 2];
for (int i = 0; i < returnBytes.Length; i++)
{
returnBytes[i]=Convert.ToByte(hexString.Substring(i*2,2),16);
}
return returnBytes;
}
/// <summary>
/// 获取类的属性名及其值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <returns></returns>
public static string GetPropertiesStr<T>(T t)
{
StringBuilder sb = new StringBuilder("");
if (t == null)
{
return sb.ToString();
}
System.Reflection.PropertyInfo[] properties = t.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
if (properties.Length <= 0)
{
return sb.ToString();
}
sb.Append("{");
foreach (System.Reflection.PropertyInfo property in properties)
{
string name = property.Name;
object value = property.GetValue(t, null);
if (property.PropertyType.IsValueType || property.PropertyType.Name.StartsWith("String"))
{
sb.Append($"{name}:{value},");
}
else if(property.PropertyType.IsGenericType)
{
var listVal = property.GetValue(t, null) as IEnumerable<object>;
if (listVal == null) continue;
sb.Append("[");
foreach (var item1 in listVal)
{
sb.Append(GetPropertiesStr(item1));
}
sb.Append("]");
}
else if(property.PropertyType.IsArray)
{
var listVal = property.GetValue(t, null) as IEnumerable<object>;
if (listVal == null) continue;
sb.Append("[");
foreach (var item1 in listVal)
{
sb.Append(GetPropertiesStr(item1));
}
sb.Append("]");
}
else
{
sb.Append(GetPropertiesStr(value));
}
}
sb.Append("}");
return sb.ToString();
}
}
}
using DL.Com.Protocol.Modbus;
using DL.Utils;
using log4net;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Threading;
namespace DL.Com.TCP
{
public class ModbusTCPMaster
{
List<Register> registers = new List<Register>() {
new CoilRegister(),new DiscreteInputRegister(),new HoldingRegister(),
new InputRegister()
};
public static List<string> Functions = new List<string>() {
"01 Read Coils","02 Read Discrete Inputs","03 Read Holding Registers",
"04 Read Input Registers","05 WriteSingle Coil","06 Write Single Register",
"0F Write Multiple Coils","10 Write Multiple Registers"
};
TcpClient tcpClient = new TcpClient();
Thread thread;
public delegate void ConnectionChangedHandler(string ip, int port, bool onOff);
public delegate void ReceiveDataHandler(string ip, int port, RequestInfo requestInfo, byte[] data);
public event ConnectionChangedHandler ConnectionChanged;
public event ReceiveDataHandler ReceiveData;
public bool IsAutoReconnect = false;
public int TryTimes = 5;
public string IP { get; private set; }
public int Port { get; private set; }
bool online = false;
public bool Online
{
get { return online; }
private set
{
if (online != value)
{
online = value;
ConnectionChanged?.Invoke(IP, Port, value);
}
}
}
bool start = false;
public ModbusTCPMaster()
{
start = true;
thread = new Thread(sendQueueRequest);
thread.IsBackground = true;
thread.Start();
}
~ModbusTCPMaster()
{
start = false;
}
object locsend = new object();
private const int SEND_SLEEP = 50; //每条命令发送的间隔
void sendQueueRequest()
{
while (start)
{
if (Monitor.TryEnter(locsend))
{
try
{
//Online = tcpClient.IsConnected();
if (!Online)
{
if (IsAutoReconnect)
{
online= tcpClient.Connect(IP, Port, ReceiveMessage);
Thread.Sleep(1000);
RequestInfo requestInfo = GetPeek();
if (requestInfo != null && requestInfo.Requested)
{
requestInfo.SetRequestState(false);
LogUtil.Error($"Disconnect 重置请求状态{requestInfo}");
continue;
}
}
}
else
{
SendRequest();
}
}
catch (Exception ex)
{
LogUtil.Error($"sendQueueRequest出错", ex);
}
finally
{
Monitor.Exit(locsend);
}
}
Thread.Sleep(SEND_SLEEP);
}
}
/// <summary>
/// 请求队列
/// </summary>
ConcurrentQueue<RequestInfo> requestInfos = new ConcurrentQueue<RequestInfo>();
public void Connect(string ip, int port)
{
IP = ip;
Port = port;
// tcpClient.Connect(ip, port, ReceiveMessage);
//Thread.Sleep(1000);
IsAutoReconnect = true;
}
public void Close()
{
tcpClient.Close();
}
/// <summary>
/// 添加请求
/// </summary>
/// <param name="requestInfo">请求信息</param>
public void AddRequest(RequestInfo requestInfo)
{
EnRequestQueue(requestInfo);
}
/// <summary>
/// 添加请求
/// </summary>
/// <param name="funCode"></param>
/// <param name="startAddr"></param>
/// <param name="countOrValue"></param>
/// <param name="equpAddr"></param>
/// <param name="values"></param>
public void AddRequest(byte funCode, int startAddr, int countOrValue, byte equpAddr = 1, int[] values = null)
{
EnRequestQueue(new RequestInfo()
{
FunCode = funCode,
StartAddr = startAddr,
CountOrValue = countOrValue,
EquipAddr = equpAddr,
Values = values
});
}
/// <summary>
/// 收到数据
/// </summary>
/// <param name="msg"></param>
void ReceiveMessage(string msg, byte[] data)
{
LogUtil.Debug($"Receive Data {StringHelper.ToHexString(data)}");
List<byte[]> recvFun = Register.SplitResponse(data);
foreach (var item in recvFun)
{
LogUtil.Debug($"Process Data {StringHelper.ToHexString(item)}");
RequestInfo requestInfo = GetPeek();
if (requestInfo != null)
{
byte[] readData;
bool rtn = GetResponseResult(requestInfo.FunCode, item, out readData);
if (rtn)
{
RemovePeek(true);
if (readData != null)
{
ReceiveData?.Invoke(IP, Port, requestInfo, readData);
LogUtil.Debug($"{StringHelper.ToHexString(readData)}{requestInfo}");
}
}
else
{
rtn = GetResponseResult(requestInfo.FunCode, item, out readData,true);
if(rtn)
{
if (readData != null)
{
ReceiveData?.Invoke(IP, Port, requestInfo, readData);
LogUtil.Debug($"{StringHelper.ToHexString(readData)}{requestInfo}");
}
}
else
{
if (Register.ParseHeader(item, out byte func, out int len))
{
rtn = GetResponseResult(func, item, out readData, true);
if (rtn)
{
if (readData != null)
{
ReceiveData?.Invoke(IP, Port, new RequestInfo() { FunCode = func }, readData);
LogUtil.Debug($"{StringHelper.ToHexString(readData)}");
}
}
}
else
{
requestInfo.SetRequestState(false);
LogUtil.Error($"Request Fail {requestInfo}");
requestInfo.TryTimes++;
//if (requestInfo.TryTimes > TryTimes)//重试一定次数失败删除
//{
// RemovePeek(false);
//}
}
}
}
}
else//设备主动上传收到的信息
{
LogUtil.Debug($"Upload {StringHelper.ToHexString(item)}");
if (Register.ParseHeader(item, out byte func, out int len))
{
bool rtn = GetResponseResult(func, item, out byte[] readData,true);
if (rtn)
{
if (readData != null)
{
ReceiveData?.Invoke(IP, Port, new RequestInfo() { FunCode = func }, readData);
LogUtil.Debug($"{StringHelper.ToHexString(readData)}");
}
}
else
{
LogUtil.Error($"Upload GetResponseResult Fail {StringHelper.ToHexString(item)}");
}
}
else
{
LogUtil.Error($"Upload ParseHeader Fail {StringHelper.ToHexString(item)}");
}
}
}
}
RegisterFunction GetFunction(byte funCode)
{
Register register = GetRegister(funCode);
if (register == null)
{
LogUtil.Error($"不存在的功能码:{StringHelper.ToHexString(funCode)}");
return RegisterFunction.Read;
}
return GetFuncByByte(register, funCode);
}
/// <summary>
/// 获取请求字节数组
/// </summary>
/// <param name="funCode"></param>
/// <param name="startAddr"></param>
/// <param name="countOrValue"></param>
/// <param name="values"></param>
/// <returns></returns>
byte[] GetRequestBytes(byte funCode, int startAddr, int countOrValue, byte equipAddr, int[] values = null)
{
Register register = GetRegister(funCode);
if (register == null)
{
LogUtil.Error($"不存在的功能码:{StringHelper.ToHexString(funCode)}");
return new byte[] { 0x00 };
}
RegisterFunction registerFunction = GetFuncByByte(register, funCode);
if (values != null)
{
ushort[] tmpvalues = new ushort[values.Length];
for (int i = 0; i < values.Length; i++)
{
tmpvalues[i] = (ushort)values[i];
}
return register.GetRequestBytes(registerFunction, (ushort)startAddr, (ushort)countOrValue, equipAddr, tmpvalues);
}
return register.GetRequestBytes(registerFunction, (ushort)startAddr, (ushort)countOrValue, equipAddr, null);
}
/// <summary>
/// 获取响应结果
/// </summary>
/// <param name="funCode">功能码</param>
/// <param name="response">响应的字节数组</param>
/// <param name="data">只有读操作可以使用:读取到的数据</param>
/// <returns>true:操作成功</returns>
bool GetResponseResult(byte funCode, byte[] response, out byte[] data, bool ignoreSerial = false)
{
data = null;
Register register = GetRegister(funCode);
if (register == null)
{
LogUtil.Error($"不存在的功能码:{StringHelper.ToHexString(funCode)}");
return false;
}
RegisterFunction registerFunction = GetFuncByByte(register, funCode);
if (ignoreSerial)
return register.GetReadReault(response, out data);
else
return register.GetResult(registerFunction, response, out data);
}
RegisterFunction GetFuncByByte(Register register, byte funCode)
{
RegisterFunction registerFunction = RegisterFunction.Read;
foreach (RegisterFunction item in register.FunctionCodes.Keys)
{
if (register.FunctionCodes[item].Equals(funCode))
{
registerFunction = item;
break;
}
}
return registerFunction;
}
/// <summary>
/// 根据功能码定位置指定寄存器
/// </summary>
/// <param name="funCode"></param>
/// <returns></returns>
Register GetRegister(byte funCode)
{
return registers.Find(s => s.FunctionCodes.ContainsValue(funCode));
}
/// <summary>
/// 加入队列
/// </summary>
/// <param name="request"></param>
void EnRequestQueue(RequestInfo request)
{
requestInfos.Enqueue(request);
if (!GetFunction(request.FunCode).Equals(RegisterFunction.Read))
LogUtil.Debug($"Enqueue Request {request}");
else
LogUtil.Debug($"Enqueue Request {request}");
}
/// <summary>
/// 获取队列第一个请求
/// </summary>
/// <returns></returns>
RequestInfo GetPeek()
{
requestInfos.TryPeek(out RequestInfo request);
return request;
}
/// <summary>
/// 移除队列第一个请求
/// </summary>
/// <returns></returns>
bool RemovePeek(bool success)
{
bool rtn = requestInfos.TryDequeue(out RequestInfo request);
if (success)
{
request.Result = true;
request.FinishTime = DateTime.Now;
if (!GetFunction(request.FunCode).Equals(RegisterFunction.Read))
LogUtil.Info($"Request Success {request}");
else
LogUtil.Debug($"Request Success {request}");
}
else
{
LogUtil.Error($"Try Request {TryTimes} Times Fail {request}");
}
return rtn;
}
void SendRequest()
{
RequestInfo requestInfo = GetPeek();
if (requestInfo != null && (!requestInfo.Requested || requestInfo.RequestTimeOut))
{
try
{
bool rtn = tcpClient.Send(GetRequestBytes(requestInfo.FunCode, requestInfo.StartAddr, requestInfo.CountOrValue, requestInfo.EquipAddr, requestInfo.Values));
requestInfo.SetRequestState(rtn);
if (!GetFunction(requestInfo.FunCode).Equals(RegisterFunction.Read))
LogUtil.Debug($"Request {requestInfo}");
else
LogUtil.Debug($"Request {requestInfo}");
}
catch { online = false; }
}
}
}
/// <summary>
/// Modbus请求信息
/// </summary>
public class RequestInfo
{
/// <summary>
/// 功能码
/// </summary>
public byte FunCode { get; set; }
/// <summary>
/// 开始地址
/// </summary>
public int StartAddr { get; set; }
/// <summary>
/// 数量/值
/// </summary>
public int CountOrValue { get; set; }
/// <summary>
/// 设备地址
/// </summary>
public byte EquipAddr { get; set; }
/// <summary>
/// 数组值,写多个值用到
/// </summary>
public int[] Values { get; set; }
/// <summary>
/// 等待一定秒数反转信号。大于0,反转
/// </summary>
public int Seconds { get; set; } = 0;
/// <summary>
/// 是否请求过
/// </summary>
public bool Requested { get; set; } = false;
public int TryTimes { get; set; } = 0;
/// <summary>
/// 请求时间
/// </summary>
public DateTime RequestTime { get; set; } = DateTime.Now;
public DateTime FinishTime { get; set; }
/// <summary>
/// 请求超时
/// </summary>
public bool RequestTimeOut { get { return (DateTime.Now - RequestTime).TotalSeconds > 5; } }
/// <summary>
/// 结果
/// </summary>
public bool Result { get; set; } = false;
/// <summary>
/// 请求
/// </summary>
public void SetRequestState(bool request)
{
Requested = request;
if (request)
RequestTime = DateTime.Now;
}
public override string ToString()
{
return JsonHelper.SerializeObject(this);
}
}
}
using DL.Utils;
using log4net;
using System;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Threading;
namespace DL.Com.TCP
{
public class TcpClient
{
public delegate void HandleMessage(string message, byte[] data);
private Socket m_clientSocket = null;
private byte[] m_receiveBuffer = new byte[1024];
private HandleMessage onReceived;
public int TimeOutTime = 2000;
public string IP { get; set; }
public int Port { get; set; }
public TcpClient()
{
}
/// <summary>
/// 当前连接状态
/// </summary>
public bool IsConnected()
{
if (m_clientSocket == null)
{
return false;
}
return m_clientSocket.Connected;
//if (m_clientSocket.Connected)
//{
// return true;
//}
#region remarks
/********************************************************************************************
* 当Socket.Conneted为false时, 如果您需要确定连接的当前状态,请进行非阻塞、零字节的 Send 调用。
* 如果该调用成功返回或引发 WAEWOULDBLOCK 错误代码 (10035),则该套接字仍然处于连接状态;
* 否则,该套接字不再处于连接状态。
* Depending on http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.connected.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-2
********************************************************************************************/
#endregion
try
{
#region 过程
// This is how you can determine whether a socket is still connected.
bool connectState = true;
bool blockingState = m_clientSocket.Blocking;
try
{
byte[] tmp = new byte[1];
m_clientSocket.Blocking = false;
m_clientSocket.Send(tmp, 0, 0);
//Console.WriteLine("Connected!");
connectState = true; //若Send错误会跳去执行catch体,而不会执行其try体里其之后的代码
}
catch (SocketException e)
{
// 10035 == WSAEWOULDBLOCK
if (e.NativeErrorCode.Equals(10035))
{
connectState = true;
}
else
{
connectState = false;
}
}
finally
{
if (m_clientSocket != null && m_clientSocket.Connected)
{
m_clientSocket.Blocking = blockingState;
}
}
//Console.WriteLine("Connected: {0}", client.Connected);
return connectState;
#endregion
}
catch (Exception ex)
{
//Log.Error("IsConnected 出错", log, ex);
return false;
}
}
/// <summary>
/// 连接服务器
/// </summary>
public bool Connect(string serverIP, int serverPort, HandleMessage HandleMessage)
{
IP=serverIP;
Port=serverPort;
m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
if (TimeOutTime <= 0)
{
IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse(serverIP), serverPort);
m_clientSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
try
{
if (!m_clientSocket.Connected)
{
m_clientSocket.Connect(remoteEndPoint);
}
if (m_clientSocket.Connected)
{
m_clientSocket.BeginReceive(m_receiveBuffer, 0, m_receiveBuffer.Length, 0, new AsyncCallback(ReceiveCallBack), null);
onReceived = HandleMessage;
LogUtil.Info("Connect to " + serverIP + ":" + serverPort + " success!");
return true;
}
else
{
LogUtil.Info("Connect to " + serverIP + ":" + serverPort + " fail!");
}
}
catch (Exception ex)
{
LogUtil.Error("Connect to " + serverIP + ":" + serverPort + " fail!", ex);
//m_clientSocket = null;
}
}
else
{
m_clientSocket.ReceiveTimeout = TimeOutTime;
m_clientSocket.SendTimeout = TimeOutTime;
IAsyncResult connResult = m_clientSocket.BeginConnect(serverIP, serverPort, null, null);
connResult.AsyncWaitHandle.WaitOne(this.TimeOutTime, true); //等待2秒
if (!connResult.IsCompleted || (!m_clientSocket.Connected))
{
LogUtil.Info("Connect to " + serverIP + ":" + serverPort + " fail!");
m_clientSocket.Close();
//处理连接不成功的动作
return false;
}
else
{
//处理连接成功的动作
m_clientSocket.BeginReceive(m_receiveBuffer, 0, m_receiveBuffer.Length, 0, new AsyncCallback(ReceiveCallBack), null);
onReceived = HandleMessage;
LogUtil.Info("Connect to " + serverIP + ":" + serverPort + " success!");
return true;
}
}
return false;
}
/// <summary>
/// 断开连接
/// </summary>
public void Close()
{
try
{
if (m_clientSocket != null && m_clientSocket.Connected)
{
m_clientSocket.Shutdown(SocketShutdown.Both);
//Thread.Sleep(300);
//m_clientSocket.Disconnect(true);
//Thread.Sleep(300);
m_clientSocket.Close();
//m_clientSocket = null;
LogUtil.Info("Socket closed!");
}
else
{
LogUtil.Error("No socket is running!");
}
}
catch (Exception ex)
{
LogUtil.Error("close error", ex);
}
}
/// <summary>
/// 发送信息
/// </summary>
public void Send(string strSendData)
{
byte[] sendBuffer = new byte[1024];
sendBuffer = Encoding.UTF8.GetBytes(strSendData);
if (m_clientSocket != null && m_clientSocket.Connected)
{
m_clientSocket.Send(sendBuffer);
LogUtil.Debug("Send >> " + strSendData);
}
}
public bool Send(byte[] bytes)
{
if (m_clientSocket != null && m_clientSocket.Connected)
{
m_clientSocket.Send(bytes);
LogUtil.Debug("Send >> " + StringHelper.ToHexString(bytes));
return true;
}
return false;
}
private void ReceiveCallBack(IAsyncResult ar)
{
try
{
if (m_clientSocket != null && m_clientSocket.Connected)
{
int REnd = m_clientSocket.EndReceive(ar);
string strReceiveData = Encoding.Default.GetString(m_receiveBuffer, 0, REnd);
byte[] tmp = new byte[REnd];
Array.Copy(m_receiveBuffer, tmp, REnd);
onReceived(strReceiveData, tmp);
Thread.Sleep(100);
m_clientSocket.BeginReceive(m_receiveBuffer, 0, m_receiveBuffer.Length, 0, new AsyncCallback(ReceiveCallBack), null);
}
}
catch (Exception ex)
{
LogUtil.Error("socket received error", ex);
}
}
}
}
using DL.Utils;
using log4net;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace DL.Com.TCP
{
public class TcpServer
{
/// <summary>
/// 接受消息时的间隔
/// </summary>
public static int ReviceMsgMS = 10;
private Thread m_serverThread;
private Socket m_serverSocket;
public delegate void ReviceMsgEventHandler(TcpClientBean client, string Msg,byte[] data);
public delegate void ClientOffLineEventHandler(TcpClientBean client);
public delegate void AcceptClientEventHandler(TcpClientBean client);
public event ReviceMsgEventHandler ReviceMsgEvent;
public event AcceptClientEventHandler AcceptClientEvent;
public event ClientOffLineEventHandler ClientOfflineEvent;
private bool isRun = false;
private int serverPort = 0;
public TcpServer(int m_serverPort)
{
this.serverPort = m_serverPort;
}
private void logLocalIp()
{
string[] addresses = GetLocalAddresses();
string iplist = "本机IP:[";
if (addresses.Length > 0)
{
for (int i = 0; i < addresses.Length; i++)
{
if (addresses.Length != 0)
{
iplist = iplist + " " + addresses[i];
}
}
}
LogUtil.Info(iplist + "]");
}
public bool Connected { get { return m_serverSocket != null && m_serverSocket.Connected; } }
/// <summary>
/// 开始服务
/// </summary>
public bool Start()
{
try
{
isRun = true;
m_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, serverPort);
m_serverSocket.Bind(localEndPoint);
m_serverSocket.Listen(10);
m_serverThread = new Thread(new ThreadStart(ReceiveAccept));
m_serverThread.Start();
LogUtil.Info(" Server start listen : " + serverPort);
logLocalIp();
return true;
//this.AddRunningInfo(">> " + DateTime.Now.ToString() + " Server started.");
}
catch (SocketException se)
{
LogUtil.Error("Tcpserver Start 报错",se);
}
catch (Exception ex)
{
LogUtil.Error("Tcpserver Start 报错", ex);
}
return false;
}
/// <summary>
/// 停止服务
/// </summary>
public bool Stop()
{
try
{
isRun = false;
m_serverThread.Interrupt(); // 线程终止
m_serverSocket.Close(); // Socket Close
return true;
}
catch (Exception ex)
{
LogUtil.Error("Tcpserver Stop报错", ex);
}
return false;
}
private void ReceiveAccept()
{
while (isRun)
{
TcpClientBean client = new TcpClientBean();
try
{
client.ClientSocket = m_serverSocket.Accept();
IPEndPoint clientipe = (IPEndPoint)client.ClientSocket.RemoteEndPoint;
client.IP = clientipe.Address.ToString();
client.Port = clientipe.Port;
LogUtil.Info("[" + serverPort + "]有新的客户端连接上:[" + client.AddStr + "]");
AcceptClientEvent?.Invoke(client);
Task.Factory.StartNew(delegate { ReceiveMessages(client); });
}
catch (Exception ex)
{
LogUtil.Error("ReceiveAccept方法,客户端【" + client.AddStr + "】", ex);
//throw new Exception(ex.Message);
}
}
}
// private StringBuilder sb = new StringBuilder(); //这个是用来保存:接收到了的,但是还没有结束的消息
private int receiveBufferSize = 1024;
public string terminateString = "\r\n";
public void ReceiveMessages(TcpClientBean client) //这个函数会被以线程方式运行
{
try
{
StringBuilder sb = new StringBuilder();
Socket socket = (Socket)client.ClientSocket;
while (true)
{
byte[] buffer = new byte[receiveBufferSize]; //buffer大小,此处为1024
if(socket.Poll(0,SelectMode.SelectRead))
{
int receivedSize = socket.Receive(buffer);
if (receivedSize > 0)
{
string rawMsg = Encoding.ASCII.GetString(buffer, 0, receivedSize);
byte[] data = new byte[receivedSize];
Array.Copy(buffer, 0, data, 0, receivedSize);
int rnFixLength = terminateString.Length; //这个是指消息结束符的长度,此处为\r\n
if (rnFixLength == 0)//无结束符
{
this.ReviceMsgEvent?.Invoke(client, rawMsg, data);//无消息结束符,直接触发消息接收完成事件
}
else
{
for (int i = 0; i < rawMsg.Length;) //遍历接收到的整个buffer文本
{
if (i <= rawMsg.Length - rnFixLength)
{
if (rawMsg.Substring(i, rnFixLength) != terminateString)//非消息结束符,则加入sb
{
sb.Append(rawMsg[i]);
i++;
}
else
{
this.ReviceMsgEvent?.Invoke(client, sb.ToString(), data);//找到了消息结束符,触发消息接收完成事件
sb = new StringBuilder();
i += rnFixLength;
}
}
else
{
sb.Append(rawMsg[i]);
i++;
}
}
}
}
else
{
ClientOfflineEvent?.Invoke(client);
LogUtil.Info($"客户端【{client.AddStr}】已断开");
break;
}
}
Thread.Sleep(ReviceMsgMS);
}
}
catch (SocketException e)
{
LogUtil.Error($"客户端【{client.AddStr}】:{e.StackTrace}", e);
ClientOfflineEvent?.Invoke(client);
}
catch (Exception ex)
{
LogUtil.Error($"客户端【{client.AddStr}】:{ex.StackTrace}", ex);
ClientOfflineEvent?.Invoke(client);
}
}
//private void ReceiveMessages(Client client)
//{
// try
// {
// while (true)
// {
// byte[] receiveBuffer = new byte[1024];
// //int size = ;
// int size = client.ClientSocket.Receive(receiveBuffer);
// string strReceiveData = Encoding.ASCII.GetString(receiveBuffer, 0, size);
// if (!string.IsNullOrEmpty(strReceiveData))
// {
// Log.info(LOGGER, "收到数据:" + strReceiveData);
// // this.AddRunningInfo(">> Receive data from [" + client.ClientSocket.RemoteEndPoint.ToString()+ "]:" + strReceiveData);
// string strSendData = "OK. The content is:" + strReceiveData;
// //Log.info(LOGGER, "OK. The content is:" + strReceiveData);
// int sendBufferSize = Encoding.Unicode.GetByteCount(strSendData);
// byte[] sendBuffer = new byte[sendBufferSize];
// sendBuffer = Encoding.Unicode.GetBytes(strSendData);
// client.ClientSocket.Send(sendBuffer);
// }
// }
// }
// catch (SocketException e)
// {
// Log.error(LOGGER, e.ToString());
// }
// catch (Exception ex)
// {
// LOGGER.Error(ex.ToString());
// }
//}
/// <summary>
/// 获取本机地址列表
/// </summary>
public static string[] GetLocalAddresses()
{
// 获取主机名
string strHostName = Dns.GetHostName();
// 根据主机名进行查找
IPHostEntry iphostentry = Dns.GetHostEntry(strHostName);
List<string> retval = new List<string>();
foreach (IPAddress ipaddress in iphostentry.AddressList)
{
if (ipaddress.AddressFamily != AddressFamily.InterNetworkV6)
{
retval.Add(ipaddress.ToString());
}
}
return retval.ToArray();
}
/// <summary>
/// 端口是否被占用
/// </summary>
/// <param name="port"></param>
/// <returns></returns>
public static bool PortInUse(int port)
{
bool result = false;
IPGlobalProperties iPGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
IPEndPoint[] activeTcpListeners = iPGlobalProperties.GetActiveTcpListeners();
IPEndPoint[] array = activeTcpListeners;
for (int i = 0; i < array.Length; i++)
{
IPEndPoint iPEndPoint = array[i];
bool flag = iPEndPoint.Port == port;
if (flag)
{
string[] expr_36 = new string[5];
expr_36[0] = "IP【";
int arg_53_1 = 1;
IPAddress expr_47 = iPEndPoint.Address;
expr_36[arg_53_1] = ((expr_47 != null) ? expr_47.ToString() : null);
expr_36[2] = "】port【";
expr_36[3] = iPEndPoint.Port.ToString();
expr_36[4] = "】已使用";
LogUtil.Error(string.Concat(expr_36));
result = true;
break;
}
}
return result;
}
public bool IsOnline(string addr = "")
{
return isRun;
}
public string GetAddr()
{
return $"{string.Join(",", GetLocalAddresses())}:{serverPort}";
}
}
/// <summary>
/// 客户端会话信息类
/// </summary>
public class TcpClientBean
{
Socket m_clientSocket;
public string IP = "";
public string AddStr { get { return $"{IP}:{Port}"; } }
public int Port = 0;
public TcpClientBean() { }
public void Close()
{
if (m_clientSocket != null && m_clientSocket.Connected)
{
m_clientSocket.Shutdown(SocketShutdown.Both);
m_clientSocket.Close();
}
}
public Socket ClientSocket
{
get { return m_clientSocket; }
set { this.m_clientSocket = value; }
}
}
}

using DL.Utils;
using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace DL.Com
{
public class UdpServer
{
static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod()?.DeclaringType);
private Thread m_serverThread;
private Socket udpServer;
public delegate void ReviceMsg(EndPoint address, string Msg);
/// <summary>
/// 接受到数据事件
/// </summary>
public event ReviceMsg ReviceMsgEvent;
private bool isRun = true;
private int serverPort;
private void logLocalIp()
{
string[] addresses = GetLocalAddresses();
string iplist = "本机IP:[";
if (addresses.Length > 0)
{
for (int i = 0; i < addresses.Length; i++)
{
if (addresses.Length != 0)
{
iplist = iplist + " " + addresses[i];
}
}
}
LogUtil.Info(iplist + "]",log);
}
public UdpServer(int m_serverPort)
{
serverPort = m_serverPort;
}
/// <summary>
/// 开始服务
/// </summary>
public bool Start()
{
try
{
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, serverPort);//定义一网络端点
udpServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);//定义一个Socket
udpServer.Bind(ipep);//Socket与本地的一个终结点相关联
m_serverThread = new Thread(new ThreadStart(ReceiveData));
m_serverThread.Start();
logLocalIp();
isRun = true;
return true;
}
catch (Exception ex)
{
LogUtil.Error("启动udpserver出错" ,log,ex);
}
return false;
}
/// <summary>
/// 停止服务
/// </summary>
public bool Stop()
{
try
{
isRun = false;
m_serverThread.Interrupt(); // 线程终止
udpServer.Close(); // Socket Close
return true;
}
catch (Exception ex)
{
LogUtil.Error("Stop Udpserver出错",log,ex);
}
return false;
}
private StringBuilder sb = new StringBuilder(); //这个是用来保存:接收到了的,但是还没有结束的消息
private int receiveBufferSize = 1024;
/// <summary>
/// 结束符
/// </summary>
public string terminateString = "\r";
private void ReceiveData()
{
try
{
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);//定义要发送的计算机的地址
EndPoint Remote = (EndPoint)(sender);//
while (true)
{
byte[] buffer = new byte[receiveBufferSize];
int receivedSize = udpServer.ReceiveFrom(buffer, ref Remote);
if (receivedSize > 0)
{
string rawMsg = Encoding.ASCII.GetString(buffer, 0, receivedSize);
int rnFixLength = terminateString.Length; //这个是指消息结束符的长度,此处为\r\n
for (int i = 0; i < rawMsg.Length;) //遍历接收到的整个buffer文本
{
if (i <= rawMsg.Length - rnFixLength)
{
if (rawMsg.Substring(i, rnFixLength) != terminateString)//非消息结束符,则加入sb
{
sb.Append(rawMsg[i]);
i++;
}
else
{
this.ReviceMsgEvent.Invoke(Remote, sb.ToString());//找到了消息结束符,触发消息接收完成事件
sb = new StringBuilder();
i += rnFixLength;
}
}
else
{
sb.Append(rawMsg[i]);
i++;
}
}
}
Thread.Sleep(500);
}
}
catch (Exception ex)
{
LogUtil.Error("启动udpserver出错:" ,log,ex);
}
}
/// <summary>
/// 获取本机地址列表
/// </summary>
public string[] GetLocalAddresses()
{
// 获取主机名
string strHostName = Dns.GetHostName();
// 根据主机名进行查找
IPHostEntry iphostentry = Dns.GetHostEntry(strHostName);
string[] retval = new string[iphostentry.AddressList.Length];
int i = 0;
foreach (IPAddress ipaddress in iphostentry.AddressList)
{
if (ipaddress.AddressFamily != AddressFamily.InterNetworkV6)
{
retval[i] = ipaddress.ToString();
i++;
}
}
return retval;
}
public bool IsOnline(string addr = "")
{
return isRun;
}
public string GetAddr()
{
return $"{string.Join(",",GetLocalAddresses())}:{serverPort}";
}
}
}
...@@ -36,9 +36,6 @@ ...@@ -36,9 +36,6 @@
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Asa.IOModule.AIOBOX">
<HintPath>..\..\dll\Asa.IOModule.AIOBOX.dll</HintPath>
</Reference>
<Reference Include="Asa.RFID.HiStation"> <Reference Include="Asa.RFID.HiStation">
<HintPath>..\..\dll\Asa.RFID.HiStation.dll</HintPath> <HintPath>..\..\dll\Asa.RFID.HiStation.dll</HintPath>
</Reference> </Reference>
...@@ -48,15 +45,12 @@ ...@@ -48,15 +45,12 @@
<Reference Include="AsaPL.AgvClient"> <Reference Include="AsaPL.AgvClient">
<HintPath>..\..\dll\AsaPL.AgvClient.dll</HintPath> <HintPath>..\..\dll\AsaPL.AgvClient.dll</HintPath>
</Reference> </Reference>
<Reference Include="HFReader9CSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=AMD64"> <Reference Include="log4net, Version=2.0.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\dll\RFID\HFReader9CSharp.dll</HintPath>
</Reference>
<Reference Include="log4net, Version=1.2.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\..\dll\log4net.dll</HintPath> <HintPath>..\..\dll\log4net.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
<Reference Include="System.Web" /> <Reference Include="System.Web" />
...@@ -88,6 +82,10 @@ ...@@ -88,6 +82,10 @@
<Project>{43cdd09e-fcf3-4960-a01d-3bbfe9933122}</Project> <Project>{43cdd09e-fcf3-4960-a01d-3bbfe9933122}</Project>
<Name>Common</Name> <Name>Common</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\DL.IOModule\DL.IOModule.csproj">
<Project>{f85a7412-b5b3-4291-a448-a10564602e1a}</Project>
<Name>DL.IOModule</Name>
</ProjectReference>
<ProjectReference Include="..\LoadCVSLibrary\LoadCSVLibrary.csproj"> <ProjectReference Include="..\LoadCVSLibrary\LoadCSVLibrary.csproj">
<Project>{064bebf5-8faa-4ea2-a5f3-a06e6e7d9251}</Project> <Project>{064bebf5-8faa-4ea2-a5f3-a06e6e7d9251}</Project>
<Name>LoadCSVLibrary</Name> <Name>LoadCSVLibrary</Name>
...@@ -95,9 +93,11 @@ ...@@ -95,9 +93,11 @@
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup />
<ItemGroup> <ItemGroup>
<None Include="app.config" />
<None Include="LineConfig\FeederLineConfig.csv"> <None Include="LineConfig\FeederLineConfig.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<None Include="packages.config" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
......
using log4net; using System;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
...@@ -8,23 +7,21 @@ using System.Threading; ...@@ -8,23 +7,21 @@ using System.Threading;
using OnlineStore.Common; using OnlineStore.Common;
using OnlineStore.LoadCSVLibrary; using OnlineStore.LoadCSVLibrary;
using System.Threading.Tasks; using System.Threading.Tasks;
using Asa.IOModule; //using Asa.IOModule;
using System.Windows.Forms; using System.Windows.Forms;
using DL.IOModule;
using System.Runtime.InteropServices;
using log4net;
namespace OnlineStore.DeviceLibrary namespace OnlineStore.DeviceLibrary
{ {
public class AIOBOXManager : IOManager public class AIOBOXManager : IOManager
{ {
//public static uint DefaultDICount = 16; //public static uint DefaultDICount = 16;
//public static uint DefaultDOCount = 16; //public static uint DefaultDOCount = 16;
public readonly ILog LOGGER = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public Dictionary<string, AIOBOX> AIOMap = new Dictionary<string, AIOBOX>(); public Dictionary<string, AIOBOX> AIOMap = new Dictionary<string, AIOBOX>();
public Dictionary<string, List<Box_Sta>> DIValueMap = new Dictionary<string, List<Box_Sta>>(); public Dictionary<string, List<Box_Sta>> DIValueMap = new Dictionary<string, List<Box_Sta>>();
public Dictionary<string, List<Box_Sta>> DOValueMap = new Dictionary<string, List<Box_Sta>>(); public Dictionary<string, List<Box_Sta>> DOValueMap = new Dictionary<string, List<Box_Sta>>();
private object DIMapLock = "";
private object DOMapLock = "";
private object DILock = ""; private object DILock = "";
private object DOLock = ""; private object DOLock = "";
...@@ -85,21 +82,16 @@ namespace OnlineStore.DeviceLibrary ...@@ -85,21 +82,16 @@ namespace OnlineStore.DeviceLibrary
try try
{ {
aioBox = new AIOBOX(); aioBox = new AIOBOX();
aioBox.LogPath(Application.StartupPath + @"\logs\aio\", LogType.OnlyError);
aioBox.IP = ioIp; aioBox.IP = ioIp;
aioBox.SetType(IOType.DI, DILength, IOType.DO, DOLength);
aioBox.SetInput(Asa.IOModule.Box_Type.DI, DILength);
aioBox.SetOutput(Asa.IOModule.Box_Type.DO, DOLength);
//DI主动上传 //DI主动上传
aioBox.AutoReadInput(true); aioBox.Upload = true;
aioBox.AutoReadOutput(false, DOMS);
aioBox.DI_Changed_Event += AioBox_DI_Changed_Event; ; aioBox.DI_Changed_Event += AioBox_DI_Changed_Event; ;
aioBox.DO_Changed_Event += AioBox_DO_Changed_Event; aioBox.DO_Changed_Event += AioBox_DO_Changed_Event;
LogUtil.info("开始连接:" + logName + ":" + aioBox.ErrInfo); LogUtil.info("开始连接:" + logName);
aioBox.Connect(); aioBox.Connect();
AIOMap.Add(ioIp, aioBox); AIOMap.Add(ioIp, aioBox);
...@@ -111,20 +103,12 @@ namespace OnlineStore.DeviceLibrary ...@@ -111,20 +103,12 @@ namespace OnlineStore.DeviceLibrary
} }
catch (Exception error) catch (Exception error)
{ {
LogUtil.error(LOGGER, "连接IO模块 " + logName + " 出错:" + error.ToString()); LogUtil.error("连接IO模块 " + logName + " 出错", error);
} }
} }
private DateTime lastLogTime = DateTime.Now; private DateTime lastLogTime = DateTime.Now;
private void AioBox_Log_Out_Event(AIOBOX box, string[] s)
{
foreach (string str in s)
{
LogUtil.AIOLog.Debug("[" + box.IP + "]" + str);
}
}
private void AioBox_DI_Changed_Event(AIOBOX box, Box_Sta[] sta) private void AioBox_DI_Changed_Event(AIOBOX box, Box_Sta[] sta)
{ {
try try
...@@ -268,17 +252,17 @@ namespace OnlineStore.DeviceLibrary ...@@ -268,17 +252,17 @@ namespace OnlineStore.DeviceLibrary
bool result = aioBox.WriteDO(StartAddress, GetBox_Sta(onOff)); bool result = aioBox.WriteDO(StartAddress, GetBox_Sta(onOff));
if (!result) if (!result)
{ {
LogUtil.error("AIO WriteSingleDO [" + ioIp + "] [" + StartAddress + "] 失败:" + aioBox.ErrInfo); LogUtil.error("AIO WriteSingleDO [" + ioIp + "] [" + StartAddress + "] 失败");
} }
} }
else else
{ {
LogUtil.error(LOGGER, "WriteSingleDO出错 没有连接IO模块:" + ioIp); LogUtil.error( $"WriteSingleDO出错 没有连接IO模块:{ioIp}");
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
LOGGER.Error("AIO WriteSingleDO [" + ioIp + "] [" + StartAddress + "] 出错啦:", ex); LogUtil.error("AIO WriteSingleDO [" + ioIp + "] [" + StartAddress + "] 出错啦:", ex);
} }
} }
public override void WriteSingleDO(string ioIp, byte slaveId, ushort StartAddress, IO_VALUE onOff, int mSeconds) public override void WriteSingleDO(string ioIp, byte slaveId, ushort StartAddress, IO_VALUE onOff, int mSeconds)
...@@ -298,11 +282,11 @@ namespace OnlineStore.DeviceLibrary ...@@ -298,11 +282,11 @@ namespace OnlineStore.DeviceLibrary
try try
{ {
aioBox.WriteDO(StartAddress, aioBox.ReverseStatus(currBox_Sta)); aioBox.WriteDO(StartAddress, aioBox.ReverseStatus(currBox_Sta));
LogUtil.debug(LOGGER, "**********定时回写入 IO [" + ioIp + "] [" + StartAddress + "]值" + aioBox.ReverseStatus(currBox_Sta) + "】:"); LogUtil.debug("**********定时回写入 IO [" + ioIp + "] [" + StartAddress + "]值" + aioBox.ReverseStatus(currBox_Sta) + "】:");
} }
catch (Exception ex) catch (Exception ex)
{ {
LogUtil.error(LOGGER, "**********定时回写入 出错:", ex); LogUtil.error("**********定时回写入 出错:", ex);
} }
}; };
mytimer.AutoReset = false;//设置是否自动重启,即自动执行多次; mytimer.AutoReset = false;//设置是否自动重启,即自动执行多次;
...@@ -311,7 +295,7 @@ namespace OnlineStore.DeviceLibrary ...@@ -311,7 +295,7 @@ namespace OnlineStore.DeviceLibrary
} }
else else
{ {
LogUtil.error(LOGGER, "AIO WriteSingleDO [" + ioIp + "] [" + StartAddress + "] 出错 没有连接IO模块:" + ioIp); LogUtil.error($"AIO WriteSingleDO [{ioIp}][{StartAddress}]出错,没有连接IO模块:{ioIp}");
} }
} }
catch (Exception ex) catch (Exception ex)
...@@ -439,7 +423,7 @@ namespace OnlineStore.DeviceLibrary ...@@ -439,7 +423,7 @@ namespace OnlineStore.DeviceLibrary
} }
catch (Exception ex) catch (Exception ex)
{ {
LogUtil.error(LOGGER, " GetIOValue [" + configIO.IO_IP + "] [" + configIO.GetIOAddr() + "] 获取数据出错:", ex); LogUtil.error(" GetIOValue [" + configIO.IO_IP + "] [" + configIO.GetIOAddr() + "] 获取数据出错:", ex);
} }
return value; return value;
} }
......
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.15.0" newVersion="2.0.15.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="log4net" version="2.0.15" targetFramework="net461" />
</packages>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<configSections> <configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" /> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
...@@ -29,12 +29,12 @@ ...@@ -29,12 +29,12 @@
<file type="log4net.Util.PatternString" value="logs/FeederLine.log" /> <file type="log4net.Util.PatternString" value="logs/FeederLine.log" />
<param name="Encoding" value="UTF-8" /> <param name="Encoding" value="UTF-8" />
<appendToFile value="true" /> <appendToFile value="true" />
<param name="MaxSizeRollBackups" value="30"/> <param name="MaxSizeRollBackups" value="30" />
<!-- 切割最多文件数 --> <!-- 切割最多文件数 -->
<param name="MaximumFileSize" value="100MB"/> <param name="MaximumFileSize" value="100MB" />
<!-- 每个文件的大小 --> <!-- 每个文件的大小 -->
<param name="RollingStyle" value="Size"/> <param name="RollingStyle" value="Size" />
<param name="StaticLogFileName" value="true"/> <param name="StaticLogFileName" value="true" />
<layout type="log4net.Layout.PatternLayout"> <layout type="log4net.Layout.PatternLayout">
<conversionPattern value="[%date][%t]%-5p %m%n" /> <conversionPattern value="[%date][%t]%-5p %m%n" />
</layout> </layout>
...@@ -43,12 +43,12 @@ ...@@ -43,12 +43,12 @@
<file value="logs/TheRFID-FeederLine.log" /> <file value="logs/TheRFID-FeederLine.log" />
<param name="Encoding" value="UTF-8" /> <param name="Encoding" value="UTF-8" />
<appendToFile value="true" /> <appendToFile value="true" />
<param name="MaxSizeRollBackups" value="30"/> <param name="MaxSizeRollBackups" value="30" />
<!-- 切割最多文件数 --> <!-- 切割最多文件数 -->
<param name="MaximumFileSize" value="50MB"/> <param name="MaximumFileSize" value="50MB" />
<!-- 每个文件的大小 --> <!-- 每个文件的大小 -->
<param name="RollingStyle" value="Size"/> <param name="RollingStyle" value="Size" />
<param name="StaticLogFileName" value="true"/> <param name="StaticLogFileName" value="true" />
<layout type="log4net.Layout.PatternLayout"> <layout type="log4net.Layout.PatternLayout">
<conversionPattern value="[%date][%t]%-5p %m%n" /> <conversionPattern value="[%date][%t]%-5p %m%n" />
</layout> </layout>
...@@ -81,4 +81,12 @@ ...@@ -81,4 +81,12 @@
</providers> </providers>
</roleManager> </roleManager>
</system.web> </system.web>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.15.0" newVersion="2.0.15.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration> </configuration>
\ No newline at end of file \ No newline at end of file
...@@ -53,17 +53,15 @@ ...@@ -53,17 +53,15 @@
<ApplicationIcon>DfIcon.ico</ApplicationIcon> <ApplicationIcon>DfIcon.ico</ApplicationIcon>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Client, Version=1.0.0.1, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="log4net, Version=2.0.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\..\dll\Client.dll</HintPath>
</Reference>
<Reference Include="log4net">
<HintPath>..\..\dll\log4net.dll</HintPath> <HintPath>..\..\dll\log4net.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Configuration" /> <Reference Include="System.Configuration" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.ServiceModel" /> <Reference Include="System.ServiceModel" />
<Reference Include="System.Web" />
<Reference Include="System.Web.Extensions" /> <Reference Include="System.Web.Extensions" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
...@@ -108,6 +106,7 @@ ...@@ -108,6 +106,7 @@
<DependentUpon>Resources.resx</DependentUpon> <DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
</Compile> </Compile>
<None Include="packages.config" />
<None Include="Properties\Settings.settings"> <None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator> <Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput> <LastGenOutput>Settings.Designer.cs</LastGenOutput>
......
...@@ -23,7 +23,6 @@ namespace OnlineStore.FeederLineClient ...@@ -23,7 +23,6 @@ namespace OnlineStore.FeederLineClient
{ {
private FeederLineBean feederLine; private FeederLineBean feederLine;
public static readonly ILog LOGGER = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public FrmFeederClient() public FrmFeederClient()
{ {
Control.CheckForIllegalCrossThreadCalls = false; Control.CheckForIllegalCrossThreadCalls = false;
...@@ -41,7 +40,7 @@ namespace OnlineStore.FeederLineClient ...@@ -41,7 +40,7 @@ namespace OnlineStore.FeederLineClient
this.feederLine = LineManager.InitStore(); this.feederLine = LineManager.InitStore();
if (feederLine == null) if (feederLine == null)
{ {
LogUtil.error(LOGGER, "加载设备失败"); LogUtil.error("加载设备失败");
this.Close(); this.Close();
return; return;
} }
...@@ -168,7 +167,7 @@ namespace OnlineStore.FeederLineClient ...@@ -168,7 +167,7 @@ namespace OnlineStore.FeederLineClient
} }
catch (Exception ex) catch (Exception ex)
{ {
LogUtil.error(LOGGER, "出错:" + ex.StackTrace); LogUtil.error("出错:" + ex.StackTrace);
} }
} }
...@@ -230,7 +229,7 @@ namespace OnlineStore.FeederLineClient ...@@ -230,7 +229,7 @@ namespace OnlineStore.FeederLineClient
catch (Exception ex) catch (Exception ex)
{ {
MessageBox.Show(ex.StackTrace, "Exception(异常)", MessageBoxButtons.OK, MessageBoxIcon.Error); MessageBox.Show(ex.StackTrace, "Exception(异常)", MessageBoxButtons.OK, MessageBoxIcon.Error);
LogUtil.error(LOGGER, ex.StackTrace); LogUtil.error(ex.StackTrace);
} }
} }
......
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="log4net" version="2.0.15" targetFramework="net461" />
</packages>
\ No newline at end of file \ No newline at end of file
...@@ -33,12 +33,14 @@ ...@@ -33,12 +33,14 @@
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="log4net, Version=1.2.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL"> <Reference Include="log4net, Version=2.0.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\..\dll\log4net.dll</HintPath> <HintPath>..\..\dll\log4net.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Web" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
...@@ -63,6 +65,9 @@ ...@@ -63,6 +65,9 @@
<Name>Common</Name> <Name>Common</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.
......
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="log4net" version="2.0.15" targetFramework="net40" />
</packages>
\ No newline at end of file \ No newline at end of file
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!