Issue while writing ModbusClient and ModbusServer together
Asked Answered
G

2

6

About the Code

I am using EasyModbus Nuget in C# Window Form Application. I am trying to fetch the changed Holding Register's Address Value through RTU(Real Time Update) using ModbusServer.

Below code connect to server.

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

Below code fetches the value of address given below Holding Register.

client.ReadHoldingRegisters(10001, 1);

So far, everything works perfectly.

I was reading about reading about Real Time Updates in EasyModbus. I found this link that can send the changed value of holding register automatically to the even handler.

Now, I have below code:

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)
{
}

When I run it, I get below error.

Only one usage of each socket address (protocol/network address/port) is normally permitted

This error is occurring because I added the ModbusServer code.

Can you please suggest why this is happening?

Glorification answered 18/9, 2019 at 2:18 Comment(0)
U
3

Your problem isn't so serious and your main problem in this line

ser.Listen();

because your previous server socket is still in bound.

let's take a looks when a listen socket is in bound ?

obvious reason is when your listening socket send/receive packets but in rare conditions it happens when OS is NOT in ideal condition(100 % cpu usage and etc) then Releasing server socket might takes a minute to be released. in this condition when you run your server again the exception

Only one usage of each socket address (protocol/network address/port) is normally permitted

happens.because , as i said before the previous server socket was not released yet.

Solution is

using different ports for different server sockets

or

use only one server socket which is initiated only once and check if it's connected or not.

// 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();
Ulrikaumeko answered 22/9, 2019 at 22:28 Comment(4)
There is no IsConnected property of object ser.Glorification
This approach makes sense too.Metalloid
Can u confirm the nuget used by you? There is no property called IsBound I am using EasyModbusTCPGlorification
@Glorification in order to have a listening server for Modbus it's NOT necessary to use Modbus listening socket just use .Net server socket.i mean combination of .net socket and EasyModbusTCP.both are equal.even .Net server socket is much more advanced than easyModbusTCPUlrikaumeko
M
1

It seems you already have a server on the port and you try to add one more. Try the code below:

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
    }
}

enter image description here

If you click AddServer more than once you get the error you described. Btw, if you click AddClient before AddServer you get another error. Add one server and then add any number of clients. Each client writes a holding register and related event is fired with a message like this:

enter image description here

Metalloid answered 22/9, 2019 at 22:2 Comment(2)
I downloaded the server exe from here: sourceforge.net/projects/easymodbustcp/#focus I have 2 test cases. 1. Open server exe and then make an instance of class ModbusServer 2. Don't open the server exe which is downloaded from above link and make an instance of ModbusServer. Both cases show exception.Glorification
@Pankaj, make sure you have only one ModbusServer instance on a port. You also can try another port.Metalloid

© 2022 - 2024 — McMap. All rights reserved.