Brpc代码分析-Server端(十)

2021SC@SDUSC

这里的req就是在Connect中创建的那个EpollOutRequest req,然后执行HandleEpollOutRequest,在EventDispatcher中去掉连接fd的epollout事件,然后执行on_epollout_event,在Connect函数中将on_epollout_event设置为了KeepWriteIfConnected,该函数实际调用如下函数。

 首先调用CheckConnected检查连接是否出错,然后调用ResetFileDescriptor完成对Socket的设置,然后在EventDispatcher注册连接fd的epollin事件以处理response,然后执行AfterAppConnected,这个函数核心如下

 启动一个bthread执行KeepWrite函数。

 req是队列头结点,回忆下之前ExecutionQueue的逻辑,1609这里是反转链表之后回收req节点的资源,因为这里是第一次写,next为null,所以不会走到这个逻辑,然后调用一次DoWrite。

 

 首先聚集多个req的iobuf到数组pieces中,然后将各个iobuf的block信息写入到iovec,然后调用writev,返回写入的长度nw,根据nw调整iobuf,因为我们使用的是非阻塞写,所以write不会阻塞,当send_buffer满导致无法写入时会返回EAGAIN,回到KeepWrite的循环中继续看。

 

然后回收除了头结点req外其他已完成写入的节点。然后将cur_tail设置为req,IsWriteComplete会判断是否queue中所有节点已经写完,如果现在头结点数据没写完或者有新加入的节点都算没有写完,如果有新加入的节点那么要执行一次链表反转,这块逻辑在execution_queue中描述已经比较详细,这里就不再赘述了。

还有一个小问题是当send_buffer已满导致返回EAGAIN时的处理策略,如上图中的1632行,此时会在epoll中加上监听该fd的epollout事件,因为当前Socket已注册过_on_edge_triggered_events,所以pollin为true,然后看下WaitEpollOut具体是怎么做的。

 首先1095行,在EventDispatcher中加上监听epollout事件,然后通过butex_wait挂起当前bthread,当被唤醒后就继续从1100行开始执行返回到KeepWrite。

 

然后看下当fd可写时,epoll返回可写事件,此时会进入HandleEpollOut,在1269行,因为该Socket的user为InputMessenger,因此这里cast会失败,走到1276行唤醒wait在该butex上的bthread。

到这里已经介绍完在没有连接到server端时,往socket里写数据是怎样的流程,再提一下,当已经连接到server端时,再调用Socket::Write时,如果当前没有bthread在写该fd,那么当前线程会写一次数据,如果没写完,则启动一个bthread后台写,这样可以尽量避免上下文切换,并且有更好的cache locality。

这个时候Socket::Write就返回了,在IssueRPC中释放了ID对象,返回到CallMethod中。

 demo中done为NULL,因此进入Join逻辑。这里就可以看出异步请求和同步请求,如果done传NULL就是同步请求,线程会被挂起,如果不传NULL就是异步请求,CallMethod直接返回。Join核心逻辑如下。

 523-529行判断CallId的版本号,若通过版本号发现rpc过程没有结束,那么通过butex_wait将该线程挂起在join_butex上。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值