Избегайте блокировки программы при использовании TCP в C / C ++ и std :: array - PullRequest
0 голосов
/ 22 октября 2019

Я использую Ubuntu, и у меня есть приложение C / C ++, которое использует WxWidgets и отправляет строку по TCP. Он работает довольно хорошо, только если маршрутизатор и соединение в порядке, в противном случае он зависает, и мне нужно вручную выйти из приложения.

Я вызываю функцию следующим образом:

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

и вот эта функция:

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

Благодаря предложениям, полученным в предыдущей теме, я использую нотацию std::array<uint8_t, 8> command1;, чтобы определить массивы для контента, отправляемого по сети, но я не могунайти решение, позволяющее моей программе работать правильно, даже если в сети есть проблемы. Я пытался использовать потоки или fork (), и это работает, но есть ли другое более простое решение для этого?

PS Когда он застревает из-за отсутствия подключения к Интернету, он блокируется здесь:

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

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

никогда не входит в условие if.

1 Ответ

1 голос
/ 22 октября 2019

Несколько опций

  1. Использовать Boost ASIO
  2. Поток / Процессы
  3. установить тайм-аут на низкий уровень (например, 5 секунд), чтобы заблокировать относительно небольшое количествоtime
  4. установить сокет без блокировки и выполнить epoll (с участием потоков) на нем.

Для 2 - попробуйте использовать потоки std, они должны быть простыми в использовании (вы также можете перейти к async + lambda и упростить поток управления с помощью фьючерсов).

Таким образом, код будет выглядетьи будет легче читать.

Для 3 и 4 - вам нужно установить неблокирование сокета и сделать опрос (либо через select, либо через epoll) - см. fnctl (.., O_NONBLOCK ..) select (). И если вы не получите ошибку, вы можете использовать сокет как есть (или, возможно, вернуть его из async и получить в будущем).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...