stephane / libmodbus

A Modbus library for Linux, Mac OS, FreeBSD and Windows
http://libmodbus.org
GNU Lesser General Public License v2.1
3.49k stars 1.76k forks source link

modbus_tcp_accept freezes in debugger [cpp] #430

Closed hanusek closed 6 years ago

hanusek commented 6 years ago

libmodbus version

libmodbus v3.1.4

OS and/or distribution

Ubuntu Linux 16.04.3 LTS

Environment

x86_64 gcc/g++ 4.9 and gcc/g++ 5.4.1

Description

Attempt to use the libmodbus library in C++ code.

Actual behaviour

The modbus_tcp_accept function freezes, stands still. The debugger does not go to the next breakpoint.

Steps to reproduce the behavior (commands or source code)

void ExampleProgram::start()
{
    std::cout << "ExampleProgram::start()" << std::endl;

    _ctx = modbus_new_tcp("127.0.0.1", 2055);
    if(_ctx == nullptr)
    {
        std::cout << "_ctx is nullptr" << std::endl;
        return;
    }
    _s      = modbus_tcp_listen(_ctx, 1);
    int res = -1;
    res     = modbus_tcp_accept(_ctx, &_s);
    if(res == -1)
    {
        return;
    }
    _mbMapping = modbus_mapping_new(MODBUS_MAX_READ_BITS, 0, MODBUS_MAX_READ_REGISTERS, 0);
    if(_mbMapping == nullptr)
    {
        std::cout << "_mbMapping is nullptr" << std::endl;
        // fprintf(stderr, "Failed to allocate the mapping: %s\n", modbus_strerror(errno));
        modbus_free(_ctx);
        return;
    }
    std::cout << "ExampleProgram::start() end" << std::endl;
}

libmodbus output with debug mode enabled

Debugging starts
Opening : /home/mhanusek/work/VersionControl/OpenPAC/build-pac-Desktop_Qt_5_9_1_GCC_64bit-Debug/ExampleProgram/libexample-program.so
ExampleProgram::start()
pboettch commented 6 years ago

Did you try to connect a client to your server? The expected behavior is that modbus_tcp_accept(_ctx, &_s); will block until a client is connecting.

If you want something not blocking your main-thread try to use std::thread and poll() (as I describe here as an example).

sritam2 commented 6 years ago

@pboettch: I agree to your answer as my application also behaved the same. In my case there is no pending connection initially as no client is initiating a connection at the start. But server is first trying to initialize all its components and 1 of the components is modbus-tcp. But the call to "modbus_tcp_accept()"is becoming blocking. Is there any alternative way to make the call non-blocking or do I need to go for a multi-threading approach. Is there any signal or event notification mechanism. Looking forward to your valuable advise.

Thanks and Regards, Sritam Paltasingh.

pboettch commented 6 years ago

@sritam2 The question you should ask yourself is, how much time is passing by between the "initialization of all its components" and the first client connection you want to handle and is this duration really critical to your system's behavior?

In general, in embedded software architectures you should avoid mixing up too many components in one application process (even with threads). This kind of architecture quickly leads to monster-processes which if they are crashing, nothing works anymore.

Think IPC or RPC.

sritam2 commented 6 years ago

@pboettch: thank you so much for your valuable feedback. I will think of RPC or IPC or signal notification mechanism for handling my usecase. Actually I am using libevent API library. I create many events which are controlled(what I mean is the scheduling of call back routines associated with each event) by an event handler algorithm/subroutine. But if any call-back, associated with any event, makes blocking call then the event handler algorithm/subroutine cannot run other call backs as my entire project is a single threaded application. I will look for IPC or RPC or signal handler options (provided by linux kernel).

Thanks and Regards, Sritam Paltasingh.

pboettch commented 6 years ago

Oh, I get it, it's only about the blocking aspect of accept().

Well, you can use the server-socket with poll() or select() to check whether there is activity on the socket. This, together with a timeout give you a kind of non-blocking behavior. You can also check whether the socket-option O_NONBLOCK works on server-sockets.

sritam2 commented 6 years ago

@pboettch: I am sorry for my late reply. I did investigation. if I change my server socket flag settings from O_BLOCK to O_NONBLOCK then my call to "modbus_tcp_accept()", which will eventually call accept() or accept4(), will fail if no client connection is there(which is my use case). Again I need to manually call modbus_tcp_accept() till it succeeds. So, best is to call poll() or select(). I will do further investigation and tell you the results.

Thanks and Regards, Sritam Paltasingh.