TCP C отправляет данные, когда не получает данные - PullRequest
0 голосов
/ 21 мая 2019

Я пытаюсь отправить данные подключенному клиенту, даже если клиент не отправил мне сообщение первым.

Это мой текущий код:

while (true) {
    // open a new socket to transmit data per connection
    int sock;
    if ((sock = accept(listen_sock, (sockaddr *) &client_address, &client_address_len)) < 0) {
        logger.log(TYPE::ERROR, "server::could not open a socket to accept data");
        exit(0);
    }

    int n = 0, total_received_bytes = 0, max_len = 4096;
    std::vector<char> buffer(max_len);

    logger.log(TYPE::SUCCESS,
               "server::client connected with ip address: " + std::string(inet_ntoa(client_address.sin_addr)));

    // keep running as long as the client keeps the connection open
    while (true) {
        n = recv(sock, &buffer[0], buffer.size(), 0);
        if (n > 0) {
            total_received_bytes += n;

            std::string str(buffer.begin(), buffer.end());

            KV key_value = kv_from(vector_from(str));

            messaging.set_command(key_value);
        }

        std::string message = "hmc::" + messaging.get_value("hmc") + "---" + "sonar::" + messaging.get_value("sonar") + "\n";
        send(sock, message.c_str(), message.length(), 0);
    }

    logger.log(TYPE::INFO, "server::connection closed");
    close(sock);
}

Я подумал, переместив n = recv(sock, &buffer[0], buffer.size(), 0); за пределы условия while, что он будет отправлять данные на неопределенный срок, но это не то, что произошло.

Заранее спасибо.

Решение

Добавление MSG_DONTWAIT к функции recv разрешило неблокирующие операции, которые я искал.

1 Ответ

1 голос
/ 21 мая 2019

Сначала я объясню, почему это не работает, затем я внесу предложение по решениям. В основном вы найдете ответ в man-страницах man7.org> Linux> и для recv, в частности здесь .

Когда вызывается функция "recv", она не вернется, пока данные не станут доступны и могут быть прочитаны. Такое поведение функций называется «блокировкой». Значит, текущий поток выполнения блокируется до тех пор, пока данные не будут прочитаны.

Итак, вызывая функцию

n = recv(sock, &buffer[0], buffer.size(), 0);

как и вы, вызывает проблемы. Вам также необходимо проверить код возврата. 0 означает, что соединение закрыто, -1 означает ошибку, и вы должны проверить errno для получения дополнительной информации.

Вы можете изменить сокет для работы в неблокирующем режиме с помощью функции fnctl и флага O_NONBLOCK для времени жизни сокета. Вы также можете использовать флаг MSG_DONTWAIT в качестве 4-го параметра (флаги), чтобы разблокировать функцию для каждого вызова функции.

В обоих случаях, если данные недоступны, функции возвращают -1, и вам нужно проверить errno для EAGAIN или EWOULDBLOCK.

Возвращаемое значение 0 указывает, что соединение было закрыто.

Но с точки зрения архитектуры я бы не рекомендовал использовать этот подход. Вы можете использовать несколько потоков для получения и отправки данных или, используя Linux, одну из функций выбора, опроса или аналогичных функций. Для этого есть даже общий шаблон дизайна. Он называется «Реактор». Есть также похожие шаблоны, такие как «Acceptor / Connector» и «Proactor» / «ACT». Если вы планируете написать более надежное приложение, вы можете рассмотреть его.

Здесь вы найдете реализацию Acceptor, Connector, Reactor, Proactor, ACT здесь

Надеюсь, это поможет

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