【问题标题】:Accepting multiple connections on a boost asio tcp socket在 boost asio tcp 套接字上接受多个连接
【发布时间】:2019-01-11 10:25:42
【问题描述】:

我想在一个套接字上接受两次

也就是说,我监听一个端口(一个未连接的套接字),最后想得到两个连接的套接字。

换一种说法,如果我在同一个 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 套接字接口的比较

我将在下面解释其余部分,但这说明了要点。 ACCEPT(2) 看起来像这样:

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

返回值,如果非零,是连接套接字的文件描述符。也就是说,如果我在主机H上,监听端口P,那么sockfd代表一个未连接的socket,

(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() 有关。

【问题讨论】:

    标签: c++ c++14 boost-asio


    【解决方案1】:

    你可以这样做:

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

    在这种情况下,您将获得一个 new_socket 对象,它表示已接受的连接。我是从这个example 拿来的。

    希望我正确理解了您的问题。

    【讨论】:

    • 谢谢,我认为这正是我对async_accept() 的误解:我传递给它的套接字是一个 返回 值,而不是我想要接受的未连接套接字。我需要玩一会儿以确认我理解。 (我也有点不确定提供的套接字的所有权,因为你指出了一个右值。)
    • 公平地说,旧版本没有这个选项,socket 将被传入。确实,移动必须稍后完成/套接字必须动态分配:boost.org/doc/libs/1_65_0/doc/html/boost_asio/example/cpp11/…。接受一个右值可以让所有权变得清晰:除了转让所有权之外别无他法
    猜你喜欢
    • 2012-11-10
    • 2020-05-22
    • 1970-01-01
    • 2021-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多