博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Wangle源码分析:ClientBootstrap
阅读量:7119 次
发布时间:2019-06-28

本文共 4854 字,大约阅读时间需要 16 分钟。

hot3.png

ClientBootstrap介绍

      ClientBootstrap是wangle作为Client端的一个快速启动辅助类,在经过简单的配置(builder模式)之后,便可以通过调用connect方法异步建立一个连接。

示例

    以官方提供了Echo demo为例,从宏观看一下ClientBootstrap的基本用法。

typedef Pipeline
EchoPipeline;class EchoPipelineFactory : public PipelineFactory
{ public: EchoPipeline::Ptr newPipeline(std::shared_ptr
sock) { auto pipeline = EchoPipeline::create(); pipeline->addBack(AsyncSocketHandler(sock)); pipeline->addBack(EventBaseHandler()); // ensure we can write from any thread pipeline->addBack(LineBasedFrameDecoder(8192, false)); pipeline->addBack(StringCodec()); pipeline->addBack(EchoHandler()); pipeline->finalize(); return pipeline; }};int main(int argc, char** argv) { google::ParseCommandLineFlags(&argc, &argv, true); ClientBootstrap
client; client.group(std::make_shared
(1)); client.pipelineFactory(std::make_shared
()); auto pipeline = client.connect(SocketAddress(FLAGS_host, FLAGS_port)).get(); try { while (true) { std::string line; std::getline(std::cin, line); if (line == "") { break; } pipeline->write(line + "\r\n").get(); if (line == "bye") { pipeline->close(); break; } } } catch (const std::exception& e) { std::cout << exceptionStr(e) << std::endl; } return 0;}

    可以看到,ClientBootstrap相对于ServerBootstrap(  ))而言使用形式几乎相同,首先都需要传递一个模板参数,该参数是新连接的Pipeline的类型,同样还需要设置用于穿件该类型Pipeline的工厂。不同之处在于,ServerBootstrap可以设置acceptor(boss)线程池和io(worker)线程池,ClientBootstrap只需要设置io线程池(不设置时使用默认值)。配置完成之后,便可以调用ClientBootstrap的connect方法建立连接,注意,此处的connect方法是异步的(返回值为一个folly::Future<Pipeline*>),此处直接调用Future的get()方法同步等待连接建立结束。连接一旦建立成,get将返回新连接对应的Pipeline,便可以使用Pipeline的wirte进行消息的发送。(注:Wangle中的Pipeline其实兼有了Netty中的Channel的角色)。

connect源码分析

      首先,connect源码本身并不多,如下:

folly::Future
connect( const folly::SocketAddress& address, std::chrono::milliseconds timeout = std::chrono::milliseconds(0)) override { // 如果指定了io线程池,就从IO线程池中取eventbase,否则就从folly::EventBaseManager取 auto base = (group_) ? group_->getEventBase() : folly::EventBaseManager::get()->getEventBase(); // 定义一个future,用于异步获取connect结果(值为一个pipeline*) folly::Future
retval((Pipeline*)nullptr); base->runImmediatelyOrRunInEventBaseThreadAndWait([&](){ // 定义一个异步socket std::shared_ptr
socket; if (this->sslContext_) { auto sslSocket = folly::AsyncSSLSocket::newSocket(this->sslContext_, base); if (this->sslSession_) { sslSocket->setSSLSession(this->sslSession_, true); } socket = sslSocket; } else { // 创建一个异步socket socket = folly::AsyncSocket::newSocket(base); } // 定义promise并获取future folly::Promise
promise; retval = promise.getFuture(); // 发起异步连接,并将promise传给异步回调 socket->connect( new ConnectCallback(std::move(promise), this), address, timeout.count()); // pipeline_ = pipelineFactory_->newPipeline(socket); this->makePipeline(socket); }); return retval;// 返回这个future }

       首先,是设置IO线程池,要么是使用group方法手动设置的,要么就是通过folly::EventBaseManager::get()->getEventBase()获取的(当前线程中的EventBase),然后在IO线程中runImmediatelyOrRunInEventBaseThreadAndWait运行了一个lambda函数,该函数首先创建了一个AsyncSocket(此处先不考虑SSL),然后直接调用AsyncSocket的connect方法,这里的connect本身也是异步的,它一共需要三个参数:连接回调函数ConnectCallback、要连接的对端地址SocketAddress、以及可选的超时参数timeout。这里着重关注一下ConnectCallback,因为它是异步拿到连接结果的唯一途径:

class ConnectCallback : public folly::AsyncSocket::ConnectCallback {   public:    // 异步连接的回调    ConnectCallback(folly::Promise
promise, ClientBootstrap* bootstrap) : promise_(std::move(promise)) , bootstrap_(bootstrap) {} void connectSuccess() noexcept override { if (bootstrap_->getPipeline()) { bootstrap_->getPipeline()->transportActive();// 在pipeline中传播Active事件 } promise_.setValue(bootstrap_->getPipeline()); // 设置promise,值为pipeline delete this; } void connectErr(const folly::AsyncSocketException& ex) noexcept override { promise_.setException( // 设置promise,值为对应的异常 folly::make_exception_wrapper
(ex)); delete this; } private: folly::Promise
promise_; // 持有的promise ClientBootstrap* bootstrap_; // 绑定的ClientBootstrap };

      可以看到,ConnectCallback一共需要两个构造参数:folly::Promise<Pipeline*>用来异步设置结果、ClientBootstrap。不同的connect结果将回调ConnectCallback的不同方法(成功时回调connectSuccess、失败时回调connectErr),在不同的回调方法中,会把相应的结果填充到传进来的promise中(连接正常时填充值setValue为pipeline,连接异常时填充异常setException),此时外层的Future便可以拿到异步结果。如果连接成功且ClientBootstrap中已经创建了Pipeline,那么此时会在这个Pipeline中传递transportActive事件。那么什么时候创建这个Pipeline呢?就在connect之后,会使用pipelineFactory_(前文设置)的newPipeline进行创建。connect最终会把Future返回给外层使用。

               175709_QNgX_2896894.png

 

本系列文章

 

 

 

 

 

转载于:https://my.oschina.net/fileoptions/blog/881191

你可能感兴趣的文章
[转] js对象监听实现
查看>>
【leetcode】714. Best Time to Buy and Sell Stock with Transaction Fee
查看>>
mongoDB 3.0 安全权限访问控制
查看>>
电子数字 网易游戏在线笔试 第一题 hihocoder
查看>>
Java 中nextLine()方法没有执行直接跳过解决办法
查看>>
重写和重载
查看>>
本表收录的字符的Unicode编码范围为19968至40869
查看>>
PHP多次调用Mysql存储过程报错解决办法
查看>>
leetcode-680-Valid Palindrome II
查看>>
android adb shell 常用命令
查看>>
判断文件大小的函数
查看>>
最近找到了一个免费的python教程,两周学会了python开发【内附学习视频】
查看>>
JHipster生成微服务架构的应用栈(三)- 业务微服务示例
查看>>
php用curl获取远端网页内容
查看>>
selenium+python谷歌驱动配置
查看>>
oralce的function处理考勤时间节点以及计算工作时间
查看>>
(三)、一步一步学GTK+之布局
查看>>
43. ExtJs控件属性配置详细
查看>>
ros名称、命名空间和重映射
查看>>
系统进程查看 --- 微软官方出品
查看>>