【问题标题】:Issue while writing ModbusClient and ModbusServer together一起编写 ModbusClient 和 ModbusServer 时出现问题
【发布时间】:2023-03-21 14:43:01
【问题描述】:

关于代码

我在 C# 窗口窗体应用程序中使用 EasyModbus Nuget。我正在尝试使用 ModbusServer 通过 RTU(实时更新)获取更改后的保持寄存器的地址值。

以下代码连接到服务器。

void Connect() {
    ModbusClient client = null;
    client = new ModbusClient("IP Address", 502);
    client.Connect();
}

以下代码获取保存寄存器下面给出的地址值。

client.ReadHoldingRegisters(10001, 1);

到目前为止,一切正常。

我正在阅读有关 EasyModbus 中实时更新的信息。 I found this link that can send the changed value of holding register automatically to the even handler.

现在,我有以下代码:

void Connect() {
    ModbusServer ser = new ModbusServer();
    ser.Port = Convert.ToInt32(Settings.Default.Port);
    ser.Listen();
    ser.HoldingRegistersChanged += Ser_HoldingRegistersChanged;

    ModbusClient client = null;
    client = new ModbusClient("IP Address", 502);
    client.Connect();
}


private void Ser_HoldingRegistersChanged(int register, int numberOfRegisters)
{
}

当我运行它时,我得到以下错误。

每个套接字地址(协议/网络地址/端口)只能使用一次 通常是允许的

这个错误是因为我添加了 ModbusServer 代码。

您能说明为什么会这样吗?

【问题讨论】:

    标签: c# modbus-tcp easy-modbus


    【解决方案1】:

    您的端口上似乎已经有一个服务器,您尝试再添加一个。试试下面的代码:

    public partial class Form1 : Form
    {
        private int register = 0;
        private readonly int port = 502;
        private readonly List<ModbusServer> servers = new List<ModbusServer>();
        private readonly List<ModbusClient> clients = new List<ModbusClient>();
    
        public Form1()
        {
            InitializeComponent();
            AppDomain.CurrentDomain.FirstChanceException +=
                (sender, e) => MessageBox.Show(e.Exception.Message);
        }
    
        private void Foo(object sender, ThreadExceptionEventArgs e)
        {
            MessageBox.Show(e.Exception.Message);
        }
    
        private void Ser_HoldingRegistersChanged(int register, int numberOfRegisters) =>
            MessageBox.Show($"register: {register}, numberOfRegisters: {numberOfRegisters}");
    
        private void AddServer_Click(object sender, EventArgs e) =>
            AddServerMethod();
    
        private void AddClient_Click(object sender, EventArgs e) =>
            AddClientMethod();
    
        private void AddServerMethod()
        {
            var server = new ModbusServer { Port = port };
            server.Listen();
            server.HoldingRegistersChanged += Ser_HoldingRegistersChanged;
            servers.Add(server);
            MessageBox.Show("Server added.");
            server.holdingRegisters[0] = 11; // register is changed, but no event is fired
        }
    
        private void AddClientMethod()
        {
            var client = new ModbusClient("127.0.0.1", port);
            client.Connect();
            clients.Add(client);
            MessageBox.Show("Client added.");
            client.WriteSingleRegister(register++, 11); // event is fired
        }
    }
    

    如果您多次单击AddServer,则会收到您描述的错误。顺便说一句,如果您在AddServer 之前单击AddClient,则会出现另一个错误。添加一台服务器,然后添加任意数量的客户端。每个客户端写入一个保持寄存器,相关事件被触发,消息如下:

    【讨论】:

    • 我从这里下载了服务器 exe:sourceforge.net/projects/easymodbustcp/#focus 我有 2 个测试用例。 1.打开服务器exe,然后创建一个ModbusServer类的实例 2.不要打开从上面链接下载的服务器exe,创建一个ModbusServer的实例。两种情况都显示异常。
    • @Pankaj,确保你在一个端口上只有一个ModbusServer实例。您也可以尝试其他端口。
    【解决方案2】:

    你的问题不是那么严重,你的主要问题在这一行

    ser.Listen();
    

    因为您之前的服务器套接字仍处于绑定中。

    让我们看看监听套接字何时绑定?

    明显的原因是当您的侦听套接字发送/接收数据包时,但在极少数情况下,当操作系统不处于理想状态(100% cpu 使用率等)时会发生这种情况,然后释放服务器套接字可能需要一分钟才能释放。在这种情况下,当您再次运行服务器时,异常

    每个套接字地址(协议/网络地址/端口)只能使用一次 通常是允许的

    happens.because ,正如我之前所说的,之前的服务器套接字还没有释放。

    解决办法是

    为不同的服务器套接字使用不同的端口

    只使用一个只启动一次的服务器套接字并检查它是否已连接。

    // create the socket
    public static Socket listenSocket = new Socket(AddressFamily.InterNetwork, 
                                            SocketType.Stream,
                                            ProtocolType.Tcp);
    
    // bind the listening socket to the port
    IPAddress hostIP = (Dns.Resolve(IPAddress.Any.ToString())).AddressList[0];
    IPEndPoint ep = new IPEndPoint(hostIP, port);
    if(!listenSocket.IsBound){
      listenSocket.Bind(ep);     
      // start listening
      listenSocket.Listen(backlog);
    }
    // connect client 
    ModbusClient client = null;
    client = new ModbusClient(hostIP , port);
    client.Connect();
    

    【讨论】:

    • 对象序列没有IsConnected属性。
    • 这种方法也很有意义。
    • 你能确认你使用的nuget吗?没有名为IsBound 的属性我正在使用EasyModbusTCP
    • @Pankaj 为了拥有 Modbus 的侦听服务器,不必使用 Modbus 侦听套接字,只需使用 .Net 服务器套接字。我的意思是 .net 套接字和 EasyModbusTCP 的组合。两者都是 equal.even 。 Net server socket 比easyModbusTCP先进很多
    猜你喜欢
    • 1970-01-01
    • 2023-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多