Прием нескольких подключений на бустере asio tcp socket - PullRequest
0 голосов
/ 11 января 2019

хочу дважды принять по одной розетке

То есть я слушаю порт (неподключенный сокет) и хочу получить два подключенных сокета в конце.

Сказано иначе, если я принимаю дважды на одном и том же сокете tcp, у меня возникают проблемы с распознаванием различий между двумя подключенными сокетами в asio. Это на Linux.

У меня относительно простой класс tcp-сервера. Предполагается, что все клиенты, которые могут подключиться к нему, являются однородными: если сообщение ожидает отправки клиенту, и ни одно из них не подключено, его можно отправить следующему клиенту, который подключится. Это прекрасно работает с одним подключенным сокетом, но теперь мне нужно прослушивать более одного сокета (то есть два клиента будут подключаться). Предположение об однородности все еще почти верно, но теперь у меня есть дополнительное ограничение, что если сообщение является ответом кому-то, оно должно быть передано этому человеку. (Ответы часто являются благодарностями.)

Я начинаю с того, что слушаю и принимаю:

short port = kSomethingKnown;
boost::asio::io_service& io_service_;
boost::asio::ip::tcp::socket socket_(io_service_);
boost::asio::ip::tcp::acceptor acceptor_(
    io_service_,
    boost::asio::ip::tcp::endpoint(tcp::v4(), port));

acceptor_.async_accept(socket_, [this](boost::system::error_code ec) {
    if (ec) {
        // Failed to accept.  Schedule to try again (not shown).
        return;
    }
    // Accepted.
    SendMessage();   // Flush any old messages, appropriate with a single client.
    ReceiveHeader();
});

Сравнение с интерфейсом разъема BSD

Остальное я объясню ниже, но это иллюстрирует главное. ПРИНЯТЬ (2) выглядит так:

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

Возвращаемое значение, если оно не равно нулю, является файловым дескриптором подключенного сокета. То есть, если я на хосте H и слушаю порт P, то sockfd представляет собой неподключенный сокет,

(H, P, tcp, 0, 0)

и возвращенный дескриптор файла представляет собой подключенный сокет,

(H, P, tcp, H1, P1)

где H1 - клиентский хост, а P1 - (вероятно, эфемерный) порт на клиенте, который является другой стороной этого сокета. Если я успешно приму второй раз, я получу другой подключенный сокет,

(H, P, tcp, H2, P2)

, где хотя бы один из H2 и P2 отличается от H1 и P1. Я не вижу в asio, как обращаться к этим двум соединенным сокетам. Я читал исходный код, который многому учит меня о том, как работает asio, но не о том, как работает async_accept.

Вспомогательные данные

Fwiw, вот подробности отправки и приема звонков, но я думаю, что выше, это то, что мне действительно нужно. Как только я это понимаю, я использую эти подключенные розетки вместо socket_.

SendMessage() существует в форме, которая принимает сообщение (просто помещает его в очередь) и форму выше, которая обрабатывает очередь. Эта вторая форма выглядит так:

void SendMessage() {
    if (WeAreDead()) {
        // This checked that the connection seems valid,
        // we aren't being asked to shut down, etc.
        return;
    }
    if (send_queue_.empty()) {
        // Nothing to send.
        return;
    }
    boost::asio::async_write(
        socket_, boost::asio::buffer(send_queue_.front()),
        [this](boost::system::error_code ec, size_t length) {
            if (ec) {
                // Failed, schedule another attempt, not shown here.
                return;
            }
            send_queue_.pop_front();
            if (!send_queue_.empty()) {
                SendMessage();
            }
        });
}

ReceiveHeader() (и аналогичный ReceiveBody()) выглядят аналогично, причем бит ключа является вызовом, который выглядит следующим образом:

boost::asio::async_read(
    socket_, boost::asio::buffer(receive_buffer_, kTcpHeaderSize),
    boost::asio::transfer_exactly(kTcpHeaderSize),
    [this](boost::system::error_code ec, std::size_t received_length) {

Опять же, часть, которую я нахожу запутывающей, связана с async_accept().

1 Ответ

0 голосов
/ 11 января 2019

Вы можете сделать это так:

    acceptor_.async_accept(
    [this] (std::error_code ec, tcp::socket&& new_socket) {

В этом случае вы получаете объект new_socket, который представляет собой принятое соединение. Я взял это из этого примера .

Надеюсь, я правильно понял ваш вопрос.

...