0

I'm using Ubuntu and I have a C/C++ application which uses WxWidgets and sends a string over TCP. It works pretty fine only if the router and the connection are OK, otherwise it gets stuck and I need to manually quit the application.

I call the function in this way:

SendCommand ptr;
    if ( ptr.sendcommand(16,16,1) ){
    printf("Porta Aperta\n");
    } else {
    printf("Errore di comunicazione - porta non aperta\n");
    }

and this is the function:

int SendCommand::sendcommand(int relay_on, int relay_off, int stop){
    printf("eseguo la funzione nella classe\n");

    std::array<uint8_t, 8> command1;
    std::array<uint8_t, 8> command2;

    switch(relay_on){

    case 16: command1 = {0x58, 0x01, 0x12, 0x00, 0x00, 0x00, 0x10, 0x7B}; // switch on the relay 16
    break;

    }

    switch(relay_off){

    case 16: command2 = {0x58, 0x01, 0x11, 0x00, 0x00, 0x00, 0x10, 0x7A}; // switch off the relay 16
    break;

    }

    int sockfd, n;
    struct sockaddr_in servaddr;

    std::string serveraddr = "192.168.1.4";

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    if ( sockfd < 0 )
    {
        cerr << "Error creating socket! " << strerror(errno) << endl;
        return -1;

    }

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr(serveraddr.c_str());
    servaddr.sin_port = htons(3000);

    if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
    {
        cerr << "Error connecting socket!" << strerror(errno) << endl;
        close(sockfd);
        return -1;
    }

    //Relay #14 per porta bilancia
    printf("Apro la porta\n");

    int bytes_to_send1 = sizeof(command1);
    int bytes_to_send2 = sizeof(command2);
    int bytes_sent1 = 0;
    int bytes_sent2 = 0;

    do
    {
        n = send(sockfd, command1.data() + bytes_sent1, bytes_to_send1 - bytes_sent1, 0);
        if ( n < 0 )
        {
            cerr << "Error writing to socket!" << strerror(errno) << endl;
            close(sockfd);
        }
        bytes_sent1 += n;
    }
    while (bytes_sent1 < bytes_to_send1);

n=0;
sleep(stop);
do
    {
        n = send(sockfd, command2.data() + bytes_sent2, bytes_to_send2 - bytes_sent2, 0);
        if ( n < 0 )
        {
            cerr << "Error writing to socket!" << strerror(errno) << endl;
            close(sockfd);
        }
        bytes_sent2 += n;
    }
    while (bytes_sent2 < bytes_to_send2);
    close(sockfd);
n=0;


return 1;
}

Thanks to the suggestions received in a previous topic, I'm using the notation std::array<uint8_t, 8> command1;to define the arrays for the content to send over the net, but I cannot find a solution to let my program flows correctly even if there are problems on the network. I tried to use threads or fork() and it works, but is there any other easier solution for this?

P.S. When it get stuck because there is not internet connection, it blocks here:

if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
    {

        cerr << "Error connecting socket!" << strerror(errno) << endl;
        close(sockfd);
        return -1;
    }

it never enters the if condition.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
Marcus Barnet
  • 2,083
  • 6
  • 28
  • 36
  • 2
    Asynchronous programming. Non blocking functions and callbacks. – Jesper Juhl Oct 22 '19 at 17:39
  • so should I use the thread solution? I was previously starting a new thread and let him execute the function. – Marcus Barnet Oct 22 '19 at 17:44
  • 2
    In your case, [Boost 's ASIO](https://www.boost.org/doc/libs/1_71_0/doc/html/boost_asio.html) might be exactly what you are looking for. – user4581301 Oct 22 '19 at 17:45
  • can you point me towards the correct sample, please? should I use the blocking tcp client? https://www.boost.org/doc/libs/1_71_0/doc/html/boost_asio/example/cpp11/echo/blocking_tcp_echo_client.cpp ? How should I adapt it for my case? – Marcus Barnet Oct 22 '19 at 18:00
  • 1
    This one is a better model for you to work from: https://www.boost.org/doc/libs/1_71_0/doc/html/boost_asio/example/cpp03/timeouts/async_tcp_client.cpp I haven't run through it, but It looks to be fairly well explained. Any questions, feel free to ask. – user4581301 Oct 22 '19 at 18:25
  • 1
    Helpful reading on a no-boost solution: [Linux, sockets, non-blocking connect](https://stackoverflow.com/questions/17769964/linux-sockets-non-blocking-connect). I would deviate a bit from this and do most of the signalling with `select` or `epoll` because you're probably going to have to use either for the rest of the code. – user4581301 Oct 22 '19 at 18:27
  • You don't have a C/C++ application, you have a C++ application. C/C++ is not a programming language. Concerning your issue, check out ZeroMQ. It's a library that handles the networking in the background. It uses a separate protocol based on TCP though, so you need access to both sides. – Ulrich Eckhardt Oct 22 '19 at 18:46
  • @user4581301 thank you for your suggestion. However, the model seems to be very complex to me unfortunately and I can't understand how I should use it to send my data. – Marcus Barnet Oct 22 '19 at 20:55
  • 1
    Boost ASIO is pretty complicated, but that's because it's covering pretty much all of the bases. You can bang out a simple TCP client, but when you want to make it event based, things get tricky very fast no matter what you do. Good tool to have in your pocket when you need i, though. For now all you really need is a non-blocking connect and `select` or `epoll` to synchronize everything without blocking the GUI. Google up a select-based server and steal the connect idea from [Linux, sockets, non-blocking connect.](https://stackoverflow.com/questions/17769964/linux-sockets-non-blocking-connect) – user4581301 Oct 22 '19 at 21:11
  • is the select function only available on the server side? because I have no possibilities to modify the server code. I can only write the client side. The server is running on a PCB and it is embedded. – Marcus Barnet Oct 23 '19 at 07:42
  • I studied the boost non-blocking example and I was able to write my own code for the client side. It works smoothly. Thank you. I used the main example and I removed the read function since I just need to write. – Marcus Barnet Oct 23 '19 at 09:16

1 Answers1

1

Several options

  1. Use Boost ASIO
  2. Thread/Processes
  3. set timeout to low (e,g - 5 seconds) so block relatively low amount of time
  4. set socket non blocking and do epoll (involves threads) on it.

For 2 - try using std threads, should be easy to use (you can also go for async + lambda and simplify control flow using futures).

That way code will look and will be more easier to read.

For 3 & 4 - you need to set socket non blocking and do a poll (either through select or epoll) - see fnctl(.., O_NONBLOCK ..) select(). And if you get no error, then you can use the socket as it is (or maybe return it from async and get in future).

fadedreamz
  • 1,156
  • 1
  • 10
  • 19