在C ++ 11中重复std :: move on boost :: asio套接字对象 [英] Repeated std::move on an boost::asio socket object in C++11

查看:324
本文介绍了在C ++ 11中重复std :: move on boost :: asio套接字对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在探索使用boost :: asio以及C ++ 11功能。特别是,我专注于一个名为async_tcp_echo_server.cpp的示例,位于这里(代码也显示在我的问题的结尾):



http://www.boost.org/doc/libs/1_54_0/ doc / html / boost_asio / example / cpp11 / echo / async_tcp_echo_server.cpp



我的问题涉及 tcp :: socket 服务器类的成员 socket _ 。在服务器类的 do_accept()方法中, socket _ 传递给 async_accept()。 (根据asio文档, async_accept()需要 socket 作为其第一个参数,以接受连接。)到目前为止,这么好。



下一个参数是异步接受操作的回调,它是一个lambda函数。 lambda的主体构造了一个新的 session 对象,其构造函数也需要相同的 socket 。有趣的是, socket 对象不能被复制;因此在示例中,使用<$ c>传递服务器对象的 socket _ $ c> std :: move()



我理解一个且唯一 code>对象(它是服务器对象的永久成员)被移动到会话 object。好 - 套接字对象不被复制,但移动 - 大家的快乐。



调用 async_accept()?是同样 socket _ server 的成员),以前被移动,再次传递?当我们移动一个成员,留下什么?是否有无限的套接字对象的魔法喷泉?



或者是真的不那么明显发生在这里?当 socket 被移动到 session 中时,是left after / <$ c $> 的 code> socket _ 成员 server c> session 对象自己的尚未构造 socket _ 成员?我是否有意义?



摘要



代码如下。程序流相当简单。 main()构造单个服务器对象。 服务器重复调用 async_accept()。每个 async_accept()回调创建一个新的会话对象,每个对象都用一个(新鲜?) socket 。所有新鲜套接字对象来自哪里,如果他们只是(重复)从同一个套接字_

  #include< ; cstdlib> 
#include< iostream>
#include< memory>
#include< utility>
#include< boost / asio.hpp>

使用boost :: asio :: ip :: tcp;

class session
:public std :: enable_shared_from_this< session>
{
public:
session(tcp :: socket socket)
:socket_(std :: move(socket))
{}

void start(){
do_read();
}

private:
void do_read(){
auto self(shared_from_this());
socket_.async_read_some(
boost :: asio :: buffer(data_,max_length),
[this,self](boost :: system :: error_code ec,std :: size_t length)
{
if(!ec){
do_write(length);
}
}
);
}

void do_write(std :: size_t length){
auto self(shared_from_this());
boost :: asio :: async_write(
socket_,
boost :: asio :: buffer(data_,length),
[boost,system] :error_code ec,std :: size_t / * length * /)
{
if(!ec){
do_read();
}
} $ b b);
}

tcp :: socket socket_;
enum {max_length = 1024};
char data_ [max_length];
};


类服务器{
public:
服务器(boost :: asio :: io_service& io_service,短端口)
:acceptor_(io_service,tcp :: endpoint(tcp :: v4(),port))
,socket_(io_service)
{
do_accept
}

private:
void do_accept(){
acceptor_.async_accept(
socket_,
[boost] :: error_code ec)
{
if(!ec){
std :: make_shared< session>(std :: move(socket_)) - > start这个socket *的交换*
}

do_accept();
}
);
}

tcp :: acceptor acceptor_;
tcp :: socket socket_;
};


int main(int argc,char * argv []){
try {
if(argc!= 2){
std :: cerr<< Usage:async_tcp_echo_server< port> \\\
;
return 1;
}

boost :: asio :: io_service io_service;

服务器s(io_service,std :: atoi(argv [1]));

io_service.run();

} catch(std :: exception& e){
std :: cerr< Exception:<< e.what()< \\\
;
}

return 0;
}


解决方案

移动语义可以想作为资源的传递所有权。资源获取是实例化(RAII)是在对象构造时分配资源所有权并在销毁时释放那些资源的概念。移动语义允许在除了建设和销毁之外的其他时间转移资源的所有权。



在这种情况下,对象(server :: socket_)是从server :: acceptor_转移操作系统套接字资源的所有权的接收者。当客户端连接时,在async_accept()返回后的某个时间点发生传输。新连接的套接字资源被移动到socket_中,并且调用回调lambda函数。在lambda期间,套接字资源被移动到session :: socket_。 Server :: socket_只拥有微秒的一小部分资源。



移动语义允许RIAA类存在于不拥有任何资源的黄昏状态。想想在调用释放后的unique_ptr。 (它是指没有内存。)服务器:: socket_后移出仍然有空间来保存资源,但暂时没有任何东西。



最后lambda函数做的事情是调用do_accept,它再次调用async_accept()。传入对socket_的引用。当另一个客户端在将来的某个时间点连接时,async_accept()将传递新连接的操作系统套接字的所有权。


I am exploring using boost::asio along with C++11 features. In particular, I am focusing on an example called "async_tcp_echo_server.cpp", located here (code is also shown at the end of my question):

http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/example/cpp11/echo/async_tcp_echo_server.cpp

My question involves the tcp::socket member socket_ of the server class. In the do_accept() method of the server class, socket_ is passed to async_accept(). (According to the asio documentation, async_accept() requires, as its first parameter, the socket to accept the connection into.) So far, so good.

The next parameter, the callback for the asynchronous accept operation, is a lambda function. The body of the lambda constructs a new session object, whose constructor also needs the same socket. Interestingly, socket objects cannot be copied; so in the example, the socket_ object, which is a member of the server object, is passed using std::move().

I understand that the "one and only" socket_ object (which is a "permanent" member of the server object) is "moved" into the session object. Fine -- socket object is not copied, but moved -- everybody's happy.

But what happens on the next call to async_accept()? Is the same socket_ (member of server), that was previously moved, passed in again? When we "move" a member, what is left behind? Is there a magical fountain of unlimited socket objects?

Or is something really less-than-obvious happening here? When the socket is moved into the session, is the contents of the "left behind/moved from" object (socket_ member of server) swapped with the contents of the "new" session object's own "not-yet-constructed" socket_ member? Am I even making sense?

Summary

Code is below. Program flow is fairly simple. main() constructs a single server object. The server makes repeated calls to async_accept(). Each async_accept() callback creates a new session object, each constructed with a (fresh?) socket. Where do all the "fresh" socket objects come from, if they are simply (repeatedly) "moved" from the same socket_ member in the (single) server?

#include <cstdlib>
#include <iostream>
#include <memory>
#include <utility>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;

class session
: public std::enable_shared_from_this<session>
{
public:
    session( tcp::socket socket )
    : socket_( std::move( socket ) )
    {}

    void start() {
        do_read();
    }

private:
    void do_read() {
        auto self( shared_from_this() );
        socket_.async_read_some(
            boost::asio::buffer( data_, max_length ),
            [this, self]( boost::system::error_code ec, std::size_t length )
            {
                if( !ec ) {
                    do_write( length );
                }
            }
        );
    }

    void do_write( std::size_t length ) {
        auto self( shared_from_this() );
        boost::asio::async_write(
            socket_,
            boost::asio::buffer( data_, length ),
            [this, self]( boost::system::error_code ec, std::size_t /*length*/ )
            {
                if( !ec ) {
                    do_read();
                }
            }
        );
    }

    tcp::socket socket_;
    enum { max_length = 1024 };
    char data_[max_length];
};


class server {
public:
    server( boost::asio::io_service& io_service, short port )
    : acceptor_( io_service, tcp::endpoint( tcp::v4(), port ) )
    , socket_( io_service )
    {
        do_accept();
    }

private:
    void do_accept() {
        acceptor_.async_accept(
            socket_,
            [this]( boost::system::error_code ec )
            {
               if( !ec ) {
                   std::make_shared<session>( std::move( socket_ ) )->start();  // is this a *swap* of socket_ ???
               }

               do_accept();
            }
        );
    }

    tcp::acceptor acceptor_;
    tcp::socket socket_;
};


int main( int argc, char* argv[] ) {
    try {
        if( argc != 2 ) {
            std::cerr << "Usage: async_tcp_echo_server <port>\n";
            return 1;
        }

        boost::asio::io_service io_service;

        server s( io_service, std::atoi( argv[1] ) );

        io_service.run();

    } catch( std::exception& e ) {
        std::cerr << "Exception: " << e.what() << "\n";
    }

    return 0;
} 

解决方案

Move semantics can be thought of as passing ownership of resources. Resource Acquisition Is Instantiation (RAII) is the concept of assigning ownership of resources at the time of object construction and the releasing of those resources at destruction. Move semantics allow for the transfer of ownership of resources at other times besides construction and destruction.

In this case, the object (server::socket_) is the recipient of a transfer of ownership of the OS socket resource from server::acceptor_. That transfer occurs at some point after async_accept() returns, when a client connects. The newly connected socket resources are moved into socket_, and the callback lambda function is called. During the lambda, the socket resources are moved into session::socket_. Server::socket_ only owned the resource for a fraction of a microsecond.

Move semantics allow RIAA classes to exist in the twilight state of not owning any resources. Think of a unique_ptr after a call to release. (It refers to no memory.) The server::socket_ after the move out still has space to hold a resource, but for the moment it owns nothing.

The last thing the lambda function does is call do_accept, which calls async_accept() again. A reference to socket_ is passed in. When another client connects at some point in the future, async_accept() will transfer ownership of a newly connected OS socket there.

这篇关于在C ++ 11中重复std :: move on boost :: asio套接字对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆