Boost.Asio C++ Chapter_3 tcp_async

/*TCP异步客户端*/
#define MEM_FN(x)       boost::bind(&self_type::x, shared_from_this())
#define MEM_FN1(x,y)    boost::bind(&self_type::x, shared_from_this(),y)
#define MEM_FN2(x,y,z)  boost::bind(&self_type::x, shared_from_this(),y,z)
class talk_to_svr : public boost::enable_shared_from_this<talk_to_svr> , boost::noncopyable {
    typedef talk_to_svr self_type;
    talk_to_svr(const std::string & message) : sock_(service), started_(true), message_(message) {}
    void start(ip::tcp::endpoint ep) {
        sock_.async_connect(ep, MEM_FN1(on_connect,_1));
    }
public:
    typedef boost::system::error_code error_code;
    typedef boost::shared_ptr<talk_to_svr> ptr;
    static ptr start(ip::tcp::endpoint ep, const std::string &message) {
        ptr new_(new talk_to_svr(message));
        new_->start(ep);
        return new_;
    }
    void stop() {
        if ( !started_) return;
        started_ = false;
        sock_.close();
    }
    bool started() { return started_; }
    ...
private:
    ip::tcp::socket sock_;
    enum { max_msg = 1024 };
    char read_buffer_[max_msg];
    char write_buffer_[max_msg];
    bool started_;
    std::string message_; 
};
//我们需要一直使用指向talk_to_svr的智能指针,这样的话当在tack_to_svr的实例上有异步操作时,那个实例是一直活动的。
//为了避免错误,比如在栈上构建一个talk_to_svr对象的实例时,我把构造方法设置成了私有而且不允许拷贝构造(继承自boost::noncopyable)。
//我们有了核心方法,比如start(),stop()和started(),它们所做的事情也正如它们名字表达的一样。
//如果需要建立连接,调用talk_to_svr::start(endpoint, message)即可。我们同时还有一个read缓冲区和一个write缓冲区。(readbuufer和writebuffer)。
//MEM_FN 是一个方便使用的宏,它们通过shared_ptr_from_this()方法强制使用一个指向 this 的智能指针

//下面的几行代码和之前的解释非常不同:
//等同于 "sock_.async_connect(ep, MEM_FN1(on_connect,_1));"
//sock_.async_connect(ep,boost::bind(&talk_to_svr::on_connect,shared_ptr_from_this(),_1));
//sock_.async_connect(ep, boost::bind(&talk_to_svr::on_connect,this,_1));

//在上述例子中,我们正确的创建了async_connect的完成处理句柄;
//在调用完成处理句柄之前它会保留一个指向talk_to_server实例的智能指针,从而保证当其发生时talk_to_server实例还是保持活动的。
//在接下来的例子中,我们错误地创建了完成处理句柄,当它被调用时,talk_to_server实例很可能已经被释放了。 从socket读取或写入时,你使用如下的代码片段:
void do_read() {
    async_read(sock_, buffer(read_buffer_), MEM_FN2(read_complete,_1,_2), MEM_FN2(on_read,_1,_2));
}
void do_write(const std::string & msg) {
    if ( !started() ) return;
    std::copy(msg.begin(), msg.end(), write_buffer_);
    sock_.async_write_some( buffer(write_buffer_, msg.size()), MEM_FN2(on_write,_1,_2));
}
size_t read_complete(const boost::system::error_code & err, size_t bytes) {
    // 和TCP客户端中的类似
}
//do_read()方法会保证当on_read()被调用的时候,我们从服务端读取一行。
//do_write()方法会先把信息拷贝到缓冲区(考虑到当async_write发生时msg可能已经超出范围被释放),然后保证实际的写入操作发生时on_write()被调用。

void on_connect(const error_code & err) {
    if ( !err)      
        do_write(message_ + "\n");
    else
        stop();
}
void on_read(const error_code & err, size_t bytes) {
    if ( !err) {
        std::string copy(read_buffer_, bytes - 1);
        std::cout << "server echoed our " << message_ << ": " << (copy == message_ ? "OK" : "FAIL") << std::endl; 
    }
    stop(); 
}
void on_write(const error_code & err, size_t bytes) {
    do_read();
}

//当连接成功之后,我们发送消息到服务端,do_write()。当write操作结束时,on_write()被调用,它初始化了一个do_read()方法,当do_read()完成时。
//on_read()被调用;这里,我们简单的检查一下返回的信息是否是服务端的回显,然后退出服务。
int main(int argc, char* argv[]) {
    ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 8001);
    char* messages[] = { "John says hi", "so does James", "Lucy got home", 0 };
    for ( char ** message = messages; *message; ++message) {
        talk_to_svr::start( ep, *message);
        boost::this_thread::sleep( boost::posix_time::millisec(100));
    }
    service.run();
}





/*----------------------------------------------------------------------------------------------------------------*/
/*TCP异步服务端*/
class talk_to_client : public boost::enable_shared_from_this<talk_to_client>, boost::noncopyable {
    typedef talk_to_client self_type;
    talk_to_client() : sock_(service), started_(false) {}
public:
    typedef boost::system::error_code error_code;
    typedef boost::shared_ptr<talk_to_client> ptr;
    void start() {
        started_ = true;
        do_read(); 
    }

    static ptr new_() {
        ptr new_(new talk_to_client);
        return new_;
    }
    void stop() {
        if ( !started_) return;
        started_ = false;
        sock_.close();
    }
    ip::tcp::socket & sock() { return sock_;}
    ...
private:
    ip::tcp::socket sock_;
    enum { max_msg = 1024 };
    char read_buffer_[max_msg];
    char write_buffer_[max_msg];
    bool started_;
};

//因为我们是非常简单的回显服务,这里不需要is_started()方法。对每个客户端,仅仅读取它的消息,回显,然后关闭它。
//do_read(),do_write()和read_complete()方法和TCP同步服务端的完全一致。 主要的逻辑同样是在on_read()和on_write()方法中:
void do_read() {
    async_read(sock_, buffer(read_buffer_), MEM_FN2(read_complete,_1,_2), MEM_FN2(on_read,_1,_2));
}
void do_write(const std::string & msg) {
    if ( !started() ) return;
    std::copy(msg.begin(), msg.end(), write_buffer_);
    sock_.async_write_some( buffer(write_buffer_, msg.size()), MEM_FN2(on_write,_1,_2));
}
size_t read_complete(const boost::system::error_code & err, size_t bytes) {
    // 和TCP客户端中的类似
}
void on_read(const error_code & err, size_t bytes) {
    if ( !err) {
        std::string msg(read_buffer_, bytes);
        do_write(msg + "\n");
    }
    stop(); 
}
void on_write(const error_code & err, size_t bytes) {
    do_read();
}

//对客户端的处理如下:
ip::tcp::acceptor acceptor(service, ip::tcp::endpoint(ip::tcp::v4(),8001));
void handle_accept(talk_to_client::ptr client, const error_code & err)
{
    client->start();
    talk_to_client::ptr new_client = talk_to_client::new_();
    acceptor.async_accept(new_client->sock(), boost::bind(handle_accept,new_client,_1));
}
int main(int argc, char* argv[]) {
    talk_to_client::ptr client = talk_to_client::new_();
    acceptor.async_accept(client->sock(), boost::bind(handle_accept,client,_1));
    service.run();
}
//每一次客户端连接到服务时,handle_accept被调用,它会异步地从客户端读取,然后同样异步地等待一个新的客户端。
参考原文链接地址:https://mmoaay.gitbooks.io/boost-asio-cpp-network-programming-chinese/content/Chapter3.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值