brpc之InputMessenger

简介

InputMessenger类是服务端、客户端处理socket中接收消息后的处理类

类结构

InputMessageBase
-int64_t _received_us
-int64_t _base_real_us
-SocketUniquePtr _socket
-const void* _arg
#void DestroyImpl()
+void Destroy()
+Socket* ReleaseSocket()
+Socket* socket()
+const void* arg()
-void(*_process)(InputMessageBase* msg)
InputMessenger
-InputMessageHandler* _handlers
+int AddHandler(const InputMessageHandler& handler)
#void OnNewMessages(Socket* m)
-int ProcessNewMessage(Socket* m, ssize_t bytes, bool read_eof,const uint64_t received_us, const uint64_t base_realtime,InputMessageClosure& last_msg)
InputMessageHandler
Acceptor
MongoContextMessage
HttpContext
MostCommonMessage
InputResponse

InputMessageBase:是消息的基类,也是Io线程与工作线程(bthred)交互的桥梁,底层是通过SocketUniquePtr,_process是在工作线程中要做的处理,_arg表示处理时的参数。MongoContextMessage用于处理mongo的消息,HttpContext用于处理http消息,
MostCommonMessage用于处理大多数消息,InputResponse用于处理redis消息
具体的处理是交给InputMessageHandler来处理,其定义如下

struct InputMessageHandler {
    typedef ParseResult (*Parse)(butil::IOBuf* source, Socket *socket, bool read_eof, const void *arg);
    Parse parse;
    
    typedef void (*Process)(InputMessageBase* msg);
    Process process;

    typedef bool (*Verify)(const InputMessageBase* msg);
    Verify verify;

    // An argument associated with the handler.
    const void* arg;

    // Name of this handler, must be string constant.
    const char* name;
};

parse:用于解析响应
process:解析后作具体的处理
verify:主要用于process前的校验

初始化

客户端初始化

InputMessenger的创建是通过get_or_new_client_side_messenger

InputMessenger* g_messenger = NULL;
static pthread_once_t g_messenger_init = PTHREAD_ONCE_INIT;
static void InitClientSideMessenger() {
    g_messenger = new InputMessenger;
}
InputMessenger* get_or_new_client_side_messenger() {
    pthread_once(&g_messenger_init, InitClientSideMessenger);
    return g_messenger;
}

在注册完所有的Protocol后,对于协议支持处理process_response方法的,会创建对应的InputMessageHandler,将Protocol的parse和process_response添加到InputMessageHandler,最后通过AddHandler添加到InputMessenger的_handlers中

for (size_t i = 0; i < protocols.size(); ++i) {
        if (protocols[i].process_response) {
            InputMessageHandler handler;
            // `process_response' is required at client side
            handler.parse = protocols[i].parse;
            handler.process = protocols[i].process_response;
            // No need to verify at client side
            handler.verify = NULL;
            handler.arg = NULL;
            handler.name = protocols[i].name;
            if (get_or_new_client_side_messenger()->AddHandler(handler) != 0) {
                exit(1);
            }
        }
    }

服务端初始化

是通过Server::BuildAcceptor()来创建的

InputMessageHandler handler;
    std::vector<Protocol> protocols;
    ListProtocols(&protocols);
    for (size_t i = 0; i < protocols.size(); ++i) {
        if (protocols[i].process_request == NULL) {
            // The protocol does not support server-side.
            continue;
        }
        if (has_whitelist &&
            !is_http_protocol(protocols[i].name) &&
            !whitelist.erase(protocols[i].name)) {
            // the protocol is not allowed to serve.
            RPC_VLOG << "Skip protocol=" << protocols[i].name;
            continue;
        }
        // `process_request' is required at server side
        handler.parse = protocols[i].parse;
        handler.process = protocols[i].process_request;
        handler.verify = protocols[i].verify;
        handler.arg = this;
        handler.name = protocols[i].name;
        if (acceptor->AddHandler(handler) != 0) {
            LOG(ERROR) << "Fail to add handler into Acceptor("
                       << acceptor << ')';
            delete acceptor;
            return NULL;
        }
    }

列出所有的协议,看协议是否有实现process_request ,有将协议中的parse,process_request,verify赋值给InputMessageHandler添加到Acceptor中

消息处理

brpc使用的边缘触发,触发处理函数是InputMessenger的静态方法OnNewMessages

  • 调用Socket的DoRead从网络上读取数据
  • 调用InputMessenger的ProcessNewMessage来处理消息
    • 调用CutInputMessage选择正确的Prototol来解析接收到的数据
    • 创建InputMessageBase,将协议对应的process函数指针和arg赋值给_process和_arg
    • 如果对应的协议指定的verify方法则作校验操作
    • 调用QueueMessage让任务放到线程池队列中来执行处理,如果失败,则本线程来执行处理
    • 唤醒线程执行
static void QueueMessage(InputMessageBase* to_run_msg,
                         int* num_bthread_created,
                         bthread_keytable_pool_t* keytable_pool) {
    if (!to_run_msg) {
        return;
    }
    // Create bthread for last_msg. The bthread is not scheduled
    // until bthread_flush() is called (in the worse case).
                
    // TODO(gejun): Join threads.
    bthread_t th;
    bthread_attr_t tmp = (FLAGS_usercode_in_pthread ?
                          BTHREAD_ATTR_PTHREAD :
                          BTHREAD_ATTR_NORMAL) | BTHREAD_NOSIGNAL;
    tmp.keytable_pool = keytable_pool;
    if (bthread_start_background(
            &th, &tmp, ProcessInputMessage, to_run_msg) == 0) {
        ++*num_bthread_created;
    } else {
        ProcessInputMessage(to_run_msg);
    }
}

启动协程即bthread运行ProcessInputMessage,调用InputMessageBase的方法_process

void* ProcessInputMessage(void* void_arg) {
    InputMessageBase* msg = static_cast<InputMessageBase*>(void_arg);
    msg->_process(msg);
    return NULL;
}

  • 21
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kgduu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值