Modbus TCP是Modbus协议的一种变体,它是一种基于TCP/IP协议的工业通信协议。Modbus TCP协议使用标准的Ethernet网络作为物理层,支持以太网、WiFi等多种网络类型,并且提供了传统Modbus协议的数据传输方式和寻址方式,可以实现设备之间的数据交换和控制。
Modbus TCP协议的特点包括:
1. 基于TCP/IP协议,具有网络通信的可靠性和灵活性;
2. 支持多种数据类型,包括位、字节、整数、浮点数等;
3. 支持多种寻址方式,包括单个寄存器、多个寄存器、线圈等;
4. 支持多种功能码,包括读取寄存器、写入寄存器、读取线圈等;
5. 可以实现多个设备之间的数据交换和控制。
Modbus TCP协议被广泛应用于工业自动化领域,例如自动化生产线、工业机器人、智能楼宇、能源管理系统等。
Modbus TCP通信是基于TCP/IP协议的Modbus协议的一种实现方式。在Modbus TCP通信中,通信的两端分别是客户端和服务器端,客户端向服务器端发送Modbus请求,服务器端响应请求并返回数据。
Modbus TCP通信的步骤如下:
1. 建立TCP连接:客户端向服务器端发起TCP连接请求,服务器端响应请求并建立TCP连接。
2. 发送Modbus请求:客户端向服务器端发送Modbus请求,请求包括设备地址、功能码、起始地址、数据长度等信息。
3. 响应Modbus请求:服务器端接收到Modbus请求后,根据请求的内容进行处理,并返回响应数据,响应数据包括设备地址、功能码、数据长度、数据等信息。
4. 关闭TCP连接:通信完成后,客户端和服务器端都可以主动关闭TCP连接。
Modbus TCP通信中,客户端可以是任何支持TCP/IP协议的设备,例如PC、PLC、工控机等,服务器端可以是任何支持Modbus TCP协议的设备,例如传感器、执行器、控制器等。通过Modbus TCP通信,可以实现设备之间的数据交换和控制,具有广泛的应用场景。
class Program
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace UDPTest
{
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
//设置应用程序处理异常方式:ThreadException处理
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
//处理UI线程异常
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
//处理非UI线程异常
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
string str = GetExceptionMsg(e.Exception, e.ToString());
MessageBox.Show(str, "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
//LogManager.WriteLog(str);
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
string str = GetExceptionMsg(e.ExceptionObject as Exception, e.ToString());
MessageBox.Show(str, "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
//LogManager.WriteLog(str);
}
/// <summary>
/// 生成自定义异常消息
/// </summary>
/// <param name="ex">异常对象</param>
/// <param name="backStr">备用异常消息:当ex为null时有效</param>
/// <returns>异常字符串文本</returns>
static string GetExceptionMsg(Exception ex, string backStr)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("****************************异常文本****************************");
sb.AppendLine("【出现时间】:" + DateTime.Now.ToString());
if (ex != null)
{
sb.AppendLine("【异常类型】:" + ex.GetType().Name);
sb.AppendLine("【异常信息】:" + ex.Message);
sb.AppendLine("【堆栈调用】:" + ex.StackTrace);
}
else
{
sb.AppendLine("【未处理异常】:" + backStr);
}
sb.AppendLine("***************************************************************");
return sb.ToString();
}
}
}
class TCPSocket
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Timers;
namespace UDPTest
{
public enum TCPType
{
TCPServer,
TCPClient,
UDP
}
public class TCPSocket
{
#region/************* 自定义事件 捕获数据变化 *******************/
public event EventHandler BufferReceChange; //Socket接收数据事件
public event EventHandler ConnStateChange; //Socket连接状态变化事件
public event EventHandler TcpReceiveSumChange; //TCP接受数据变化事件
public event EventHandler TcpStateChange; //TCP状态变化事件
public event EventHandler TcpClientReconnect; //
private void OnBufferReceChange(EventArgs eventArgs)
{
this.BufferReceChange?.Invoke(this, eventArgs);
}
private void OnConnStateChange(EventArgs eventArgs)
{
this.ConnStateChange?.Invoke(this, eventArgs);
}
private void OnTcpReceiveSumChange(EventArgs eventArgs)
{
this.TcpReceiveSumChange?.Invoke(this, eventArgs);
}
private void OnTcpStateChange(EventArgs eventArgs)
{
this.TcpStateChange?.Invoke(this, eventArgs);
}
private void OnTcpClientReconnect(EventArgs eventArgs)
{
this.TcpClientReconnect?.Invoke(this, eventArgs);
}
#endregion
#region 参数
private bool connState = false; //连接状态
public bool _connState
{
get { return connState; }
set
{
this.OnConnStateChange(new EventArgs());
connState = value;
}
}
private string targetIp = "255.255.255.255"; //发送数据目标IP 默认值
public string _targetIP
{
get { return targetIp; }
set { targetIp = value; }
}
private int targetPort = 20019; //发送数据目标端口
public int _targetPort
{
get { return targetPort; }
set { targetPort = value; }
}
private string localIP = Utils.GetIPAddress(); //本机电脑IP
public string _localIP
{
get { return localIP; }
}
private int localProt; //本地端口
private string currentIP; //当前接收数据 IP
public string _currentIP
{
get { return currentIP; }
set { currentIP = value; }
}
private int currentPort;
private int _currentPort
{
get { return currentPort; }
set { currentPort = value; }
}
public int _localProt
{
get { return localProt; }
set { localProt = value; }
}
private long tcpReceiveSum; //网络接受数据总数
public long _tcpReceiveSum
{
get { return tcpReceiveSum; }
set
{
tcpReceiveSum = value;
this.OnTcpReceiveSumChange(new EventArgs());
}
}
private long tcpSendSum; //网络发送数据总数
public long _tcpSendSum
{
get { return tcpSendSum; }
set { tcpSendSum = value; }
}
private byte[] bufferRece; //缓存接受到的数据
public byte[] _tcpReceData
{
get { return bufferRece; }
set { bufferRece = value; }
}
private byte[] caclyBuffer;//循环发送的数据
public byte[] _caclyBuffer
{
get { return caclyBuffer; }
set { caclyBuffer = value; }
}
#endregion
Thread ReceiveData = null; //udp tcp clienct接受数据线程
UdpClient udp = new UdpClient();
//存储客户端信息
Dictionary<string, Socket> clientConnectionItems = new Dictionary<string, Socket> { }; //ip端口 套接字
public Socket _localSocket = null; //本地套接字
public Socket _targetSocket = null; //连接目标套接字
//网络通信类型 默认TCPServer
private TCPType tcpType = TCPType.TCPServer;
public TCPType _tcpType
{
get { return tcpType; }
set { tcpType = value; }
}
public TCPSocket()
{
tCPCaclyTimer.Elapsed += TcpTest_Elapsed;
}
public TCPSocket(TCPType tcp, int targerPort)
{
this._tcpType = tcp;
this._targetPort = targetPort;
}
/// <summary>
///
/// </summary>
/// <param name="tcp">通信类型</param>
/// <param name="tIP">目标IP</param>
/// <param name="tPort">目标端口</param>
/// <param name="lProt">本地IP</param>
public TCPSocket(TCPType tcp, string tIP, int tPort, int lProt)
{
this._tcpType = tcp;
this._targetIP = tIP;
this._targetPort = tPort;
this._localProt = lProt;
}
//打开网络通信
public bool tcpOpen()
{
try
{
tcpClose();
if (_tcpType == TCPType.UDP)
{
return UdpOpen();
}
else if (_tcpType == TCPType.TCPServer)
{
return OpenServer();
}
else if (_tcpType == TCPType.TCPClient)
{
return ConnServer();
}
return true;
}
catch (Exception ex)
{
return false;
}
}
//发送宿主机
public bool SendData(byte[] buffer)
{
if (_tcpType == TCPType.UDP)
{
return UdpSend(buffer);
}
else if (_tcpType == TCPType.TCPClient)
{
return tcpClientSendData(buffer);
}
else
{
return TcpServerSendData(buffer);
}
}
#region TCP server
public bool OpenServer()
{
try
{
_localSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress address = IPAddress.Parse(_localIP);//IP地址
IPEndPoint point = new IPEndPoint(address, _localProt);//IP地址端口绑定网络节点
_localSocket.Bind(point); //监听绑定的网络节点
_localSocket.Listen(20); //将套接字的监听队列长度限制为20
Thread threadwatch = new Thread(WatchConnecting);//负责监听客户端的线程
threadwatch.IsBackground = true;
threadwatch.Start();//
_connState = true;
return true;
}
catch (Exception ex)
{
_connState = false;
return false;
}
finally
{
this.OnConnStateChange(new EventArgs());
}
}
//监听客户端发来的请求
public void WatchConnecting()
{
while (true)
{
try
{
_targetSocket = _localSocket.Accept();//连接成功
}
catch (Exception ex)
{
_connState = false;
this.OnConnStateChange(new EventArgs());
break;
}
//获取客户端的IP和端口号
IPAddress clientIP = (_targetSocket.RemoteEndPoint as IPEndPoint).Address;
int clientPort = (_targetSocket.RemoteEndPoint as IPEndPoint).Port;
string remoteEndPoint = _targetSocket.RemoteEndPoint.ToString();//客户端网络节点
clientConnectionItems.Add(remoteEndPoint, _targetSocket);//客户端信息存储起来
IPEndPoint netpoint = _targetSocket.RemoteEndPoint as IPEndPoint;
//创建一个通信线程
ParameterizedThreadStart pts = new ParameterizedThreadStart(Recv);
Thread thread = new Thread(pts);
//设置为后台线程,随着主线程退出而退出
thread.IsBackground = true;
thread.Name = "ATK TcpServer网络通信线程";
thread.Start(_targetSocket); //开始通信线程
}
}
//服务端接收数据线程
public void Recv(object socketclientpara)
{
Socket socketServer = socketclientpara as Socket;
while (true)
{
if (!connState)
{
this.OnConnStateChange(new EventArgs());
break;
}
//创建一个内存缓冲区 1024字节 缓冲区太大容易丢失数据 虚拟串口处理不来
byte[] arrServerRecMsg = new byte[1024];
//将接收到的信息存入到内存缓冲区,并返回其字节数组的长度
try
{
int length = socketServer.Receive(arrServerRecMsg);
_tcpReceiveSum += length;
if (length == 0)//接收到的数据长度为0 客户端断开连接
{
clientConnectionItems.Remove(socketServer.RemoteEndPoint.ToString());
socketServer.Close();
break;
}
string Ip = "0.0.0.0";
int Point = 0;
Utils.EndPointGetIpAndPoint(socketServer.RemoteEndPoint.ToString(), out Ip, out Point);
_tcpReceData = new byte[length];
Buffer.BlockCopy(arrServerRecMsg, 0, _tcpReceData, 0, length); //TCP服务端接受的数据
this.OnBufferReceChange(new EventArgs());
}
catch (Exception ex)
{
try
{
clientConnectionItems.Remove(socketServer.RemoteEndPoint.ToString());
}
catch
{
tcpClose();
}
socketServer.Close();
break;
}
}
}
//服务端发送数据
public bool TcpServerSendData(byte[] buffer)
{
try
{
_targetSocket.Send(buffer);
return true;
}
catch (Exception ex)
{
_connState = false;
this.OnConnStateChange(new EventArgs());
return false;
}
}
#endregion
#region
//连接服务端
private bool ConnServer()
{
try
{
_targetSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//定义套接字监听
IPAddress address = IPAddress.Parse(_targetIP);//IP地址
IPEndPoint point = new IPEndPoint(address, _targetPort);//IP地址端口绑定网络节点
try
{
_targetSocket.Connect(point);
}
catch
{
_connState = false;
return false;
}
ReceiveData = new Thread(new ThreadStart(TcpClientReceiveDataThread));
ReceiveData.IsBackground = true;
ReceiveData.Name = "Tcp Client接收数据";
ReceiveData.Start();
connState = true;
return true;
}
catch (Exception ex)
{
_connState = false;
return false;
}
finally
{
this.OnConnStateChange(new EventArgs());
}
}
//tcp client接受数据线程
private void TcpClientReceiveDataThread()
{
while (true)
{
try
{
byte[] arrRecvmsg = new byte[1024];
//将客户端套接字接收到的数据存入内存缓冲区,并获取长度
int length = _targetSocket.Receive(arrRecvmsg);
if (length == 0)
{
_connState = false;
break;
}
_tcpReceiveSum += length;
_tcpReceData = new byte[length];
Buffer.BlockCopy(arrRecvmsg, 0, _tcpReceData, 0, length);
this.OnBufferReceChange(new EventArgs());
}
catch (Exception ex)
{
_connState = false;
this.OnConnStateChange(new EventArgs());
break;
}
}
}
//tcp client 发送数据
private bool tcpClientSendData(byte[] buffer)
{
try
{
_targetSocket.Send(buffer);
return true;
}
catch (Exception ex)
{
_connState = false;
this.OnConnStateChange(new EventArgs());
return false;
}
}
#endregion
#region UPD通信 连接目标主机 接受数据
//打开UDP通信
public bool UdpOpen()
{
try
{
UdpCLose();
udp = new UdpClient(0);
//_localIP = (udp.Client.LocalEndPoint as IPEndPoint).Address.ToString();
_localProt = (udp.Client.LocalEndPoint as IPEndPoint).Port;
Console.WriteLine("端口" + _localProt);
ReceiveData = new Thread(new ThreadStart(UdpReceThread));
ReceiveData.IsBackground = true;
ReceiveData.Name = "UDP 接收数据线程";
ReceiveData.Start();
connState = true;
return true;
}
catch (Exception ex)
{
_connState = false;
return false;
}
finally
{
this.OnConnStateChange(new EventArgs());
}
}
//UDP发送数据
public bool UdpSend(byte[] buffer)
{
try
{
//65 84 43 83 69 65 82 67 72 63 13 10
// udp.Send(buffer, buffer.Length, "192.168.3.255", _targetPort);
udp.Send(buffer, buffer.Length, _targetIP, _targetPort);
return true;
}
catch (Exception ex)
{
_connState = false;
this.OnConnStateChange(new EventArgs());
return false;
}
}
//UDP接收数据线程
public void UdpReceThread()
{
try
{
while (true)
{
IPEndPoint remoteIpEndPoint = null;
byte[] receiveBytes = udp.Receive(ref remoteIpEndPoint);
_currentIP = remoteIpEndPoint.Address.ToString();
_currentPort = remoteIpEndPoint.Port;
_tcpReceData = new byte[receiveBytes.Length];
Buffer.BlockCopy(receiveBytes, 0, _tcpReceData, 0, receiveBytes.Length);
this.OnBufferReceChange(new EventArgs());
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
_connState = false;
this.OnConnStateChange(new EventArgs());
}
}
#endregion
//关闭网络通信
public void tcpClose()
{
if (_tcpType == TCPType.UDP)
{
UdpCLose();
}
else if (_tcpType == TCPType.TCPClient)
{
closeTcpClent();
}
else
{
closeTcpServer();
}
_connState = false;
Thread.Sleep(100);
}
//关闭TCP Server
private void closeTcpServer()
{
try
{
foreach (var item in clientConnectionItems)
{
clientConnectionItems[item.Key].Disconnect(false);
}
_localSocket.Close();
clientConnectionItems.Clear();
}
catch (Exception)
{
}
}
//关闭TCP CLient
private void closeTcpClent()
{
try
{
if (ReceiveData != null)
{
ReceiveData.Abort();
}
_targetSocket.Close();
}
catch (Exception ex)
{
Console.WriteLine("closeTcpClent" + ex.ToString());
}
try
{
_targetSocket = null;
}
catch
{
}
}
//关闭UDp
private void UdpCLose()
{
try
{
udp.Close();
}
catch (Exception ex)
{//异常不做处理
return;
}
}
public System.Timers.Timer tCPCaclyTimer = new System.Timers.Timer(); //网络循环发送数据计时器
//重发计时器
private void TcpTest_Elapsed(object sender, ElapsedEventArgs e)
{
SendData(_caclyBuffer);
}
}
}
class Utils
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
namespace UDPTest
{
class Utils
{
//验证字符串是否为纯数字
public static bool CheckNumber(string number)
{
if (string.IsNullOrEmpty(number))
{
return false;
}
Regex regex = new Regex(@"^(-)?\d+(\.\d+)?$");
if (regex.IsMatch(number))
{
return true;
}
else
{
return false;
}
}
//验证是否为合法IP
public static bool IsIP(string ip)
{
string[] lines = ip.Split('.');
if (lines.Length != 4)
{
return false;
}
for (int i = 0; i < 4; i++)
{
if (!CheckNumber(lines[i]))
{
return false;
}
if (Convert.ToInt32(lines[i]) >= 255 || Convert.ToInt32(lines[i]) < 0)
{
return false;
}
}
return true;
}
//获取Ip
public static string GetIPAddress()
{
// 获得本机局域网IP地址
IPAddress[] AddressList = Dns.GetHostEntry(Dns.GetHostName()).AddressList;
if (AddressList.Length < 1)
{
return "";
}
for (int i = 0; i < AddressList.Length; i++)
{
if (IsIP(AddressList[i].ToString()))
{
return AddressList[i].ToString();
}
}
return "";
}
//UDP连接对象的IP 端口解析
public static bool EndPointGetIpAndPoint(string Remote, out string Ip, out int Point)
{
Ip = "0.0.0.0";
Point = 0;
string str = Remote.ToString();
try
{
string[] strList = Utils.SplitPage(str, ":");
Ip = strList[0];
Point = Convert.ToInt32(strList[1]);
return true;
}
catch (Exception ex)
{
return false;
}
}
//根据指定的标记符,分隔字符串,并返回字符数组
public static string[] SplitPage(string source, string split)
{
int len = split.Length;
ArrayList al = new ArrayList();
int start = 0; //开始位置
int j = -1; //匹配索引位置
while (true)
{
j = source.IndexOf(split, start);
if (j > -1)
{
al.Add(source.Substring(start, j - start));
int s = j - start;
start = j + len;
}
else
{
al.Add(source.Substring(start));
break;
}
}
string[] result;
if (al.Count == 0)
{
string[] r = new string[1];
r[0] = source;
result = r;
}
else
{
string[] r = new string[al.Count];
for (int i = 0; i < al.Count; i++)
{
r[i] = al[i].ToString().Trim();
}
result = r;
}
return result;
}
//byte[]数组转16字符串
public static string ByteToHexStr(byte[] by)
{
StringBuilder ret = new StringBuilder();
foreach (byte b in by)
{
//{0:X2} 大写
ret.AppendFormat("{0:X2}" + " ", b);
}
return ret.ToString();
}
//16进制字符串转Byte[]
public static byte[] hexStringToByte(string hex)
{
hex = hex.Replace(" ", "");//去掉空格
if (hex.Length % 2 == 1)
{
hex = hex.Insert(hex.Length - 1, "0");
}
byte[] b = new byte[hex.Length / 2];
for (var x = 0; x < b.Length; x++)
{
var i = Convert.ToInt32(hex.Substring(x * 2, 2), 16);
b[x] = (byte)i;
}
return b;
}
//十六进制字符串转普通字符串
public static string HexStringToDec(string hex)
{
return System.Text.Encoding.Default.GetString(hexStringToByte(hex));
}
//普通字符串转16进制字符串
public static string DecStringToHex(string dec)
{
return ByteToHexStr(System.Text.Encoding.Default.GetBytes(dec));
}
}
}
标签:return,string,通信,TCP,Modbus,new,false,public
From: https://blog.51cto.com/u_15887619/6357781