ceph Async 网络通信源代码分析(二)

在上文中,主要介绍了相关的类,本文介绍相关流程。

连接相关的流程介绍

Server端监听和接受连接的过程

这段代码来自 src/test/msgr/perf_msgr_server.cc,主要用于建立Server端的msgr:

 void start() {
    entity_addr_t addr;
    addr.parse(bindaddr.c_str());
    msgr->bind(addr);
    msgr->add_dispatcher_head(&dispatcher);
    msgr->start();
    msgr->wait();
 }

上面的代码是典型的服务端的启动流程:

  1. 绑定服务端地址 msgr->bind(addr)
  2. 添加消息分发类型 dispatcher
  3. 启动 msgr->start()

下面从内部具体如何实现。

  • 调用processor的bind 函数,对于PosixStack, 只需要一个porcessor就可以了。
int AsyncMessenger::bind(const entity_addr_t &bind_addr)
{
 ......
     for (auto &&p : processors) {
         int r = p->bind(bind_addr, avoid_ports, &bound_addr);
       }
 ......
}
int Processor::bind(const entity_addr_t &bind_addr,
            const set<int>& avoid_ports,
            entity_addr_t* bound_addr)
{
...
  //向Processor对于的工作者线程 投递外部事件,其回调函数为 worker的 listen函数
   worker->center.submit_to(worker->center.get_id(), [this, &listen_addr, &opts, &r]() {
        r = worker->listen(listen_addr, opts, &listen_socket);
      }, false);
...
}

当该外部事件被worker线程调度执行后,worker->listen完成了该Processor的listen_socket的创建。

  • 添加 dispatcher
 void add_dispatcher_head(Dispatcher *d) { 
        if (first)
      ready();
}

在ready 函数里调用了Processor::start函数

void AsyncMessenger::ready()
{
  ldout(cct,10) << __func__ << " " << get_myaddr() << dendl;

  stack->start();
  Mutex::Locker l(lock);
  for (auto &&p : processors)
    p->start();
  dispatch_queue.start();
}

在Processor::start函数里,向EventCenter 投递了外部事件,该外部事件的回调函数里实现了向 EventCenter注册listen socket 的读事件监听。 该事件的处理函数为 listen_handeler

void Processor::start()
{
  ldout(msgr->cct, 1) << __func__ << dendl;

  // start thread
  if (listen_socket) {
    worker->center.submit_to(worker->center.get_id(), [this]() {
      worker->center.create_file_event(
        listen_socket.fd(), EVENT_READABLE, listen_handler); 
    }, false);
  }
}

listen_handler对应的 处理函数为 processor::accept函数,其处理接收连接的事件。

class Processor::C_processor_accept : public EventCallback {
  Processor *pro;

 public:
  explicit C_processor_accept(Processor *p): pro(p) {}
  void do_request(int id) {
    pro->accept();
  }
};
void Processor::accept()
{
 ......
   if (!msgr->get_stack()->support_local_listen_table())
      w = msgr->get_stack()->get_worker();

    int r = listen_socket.accept(&cli_socket, opts, &addr, w);
    if (r == 0) {
      msgr->add_accept(w, std::move(cli_socket), addr);
      continue;
     }
}

在函数Processor::accept里, 首先获取了一个worker,通过调用accept函数接收该连接。并调用 msgr->add_accept 函数。

void AsyncMessenger::add_accept(Worker *w, 
                               ConnectedSocket cli_socket,
                               entity_addr_t &addr)
{
  lock.Lock();
  //创建连接,该Connection已经指定了 worker处理该Connection上所有的事件。
  AsyncConnectionRef conn = new AsyncConnection(cct, this, &dispatch_queue, w);
  conn->accept(std::move(cli_socket), addr);
  accepting_conns.insert(conn);
  lock.Unlock();
}

Client端主动连接的过程

AsyncConnectionRef AsyncMessenger::create_connect(const entity_addr_t& addr, int type)
{

  // 获取一个 worker,根据负载均衡
  Worker *w = stack->get_worker();
  //创建Connection
  AsyncConnectionRef conn = new AsyncConnection(cct, this, &dispatch_queue, w);
  //
  conn->connect(addr, type);
  //添加到conns列表中
  conns[addr] = conn;


  return conn;
}
void AsyncConnection::_connect()
{
  ldout(async_msgr->cct, 10) << __func__ << " csq=" << connect_seq << dendl;

  state = STATE_CONNECTING;
  // rescheduler connection in order to avoid lock dep
  // may called by external thread(send_message)
  center->dispatch_event_external(read_handler);
}

函数 AsyncConnection::_connect 设置了状态为 STATE_CONNECTING,向对应的 EventCenter投递 外部外部事件,其read_handler为 void AsyncConnection::process()函数。

void AsyncConnection::process()
{
   ......
    default:
        {
          if (_process_connection() < 0)
            goto fail;
          break;
        }
}
ssize_t AsyncConnection::_process_connection()
{
......
  r = worker->connect(get_peer_addr(), opts, &cs);
        if (r < 0)
          goto fail;

        center->create_file_event(cs.fd(), EVENT_READABLE, read_handler);
}

消息的接收和发送

消息的接收

消息的接收比较简单,因为消息的接收都是 内部事件,也就是都是由 epoll_wait触发的事件。其对应的回调函数 AsyncConnection::process() 去处理相应的接收事件。

消息的发送

消息的发送比较特殊,它涉及到外部事件和内部事件的相关的调用。

int AsyncConnection::send_message(Message *m){
     ......
     //把消息添加到 内部发送队列里
      out_q[m->get_priority()].emplace_back(std::move(bl), m);
     //添加外部事件给对应的的CenterEvent,并触发外部事件
      if (can_write != WriteStatus::REPLACING)
         center->dispatch_event_external(write_handler);
}

发送相关的调用函数

void AsyncConnection::handle_write()
       ssize_t AsyncConnection::write_message(Message *m,
                       bufferlist& bl, bool more)
         ssize_t AsyncConnection::_try_send(bool more)
ssize_t AsyncConnection::_try_send(bool more)
{
......
   if (!open_write && is_queued()) {
    center->create_file_event(cs.fd(), EVENT_WRITABLE, 
                            write_handler);
    open_write = true;
  }

  if (open_write && !is_queued()) {
    center->delete_file_event(cs.fd(), EVENT_WRITABLE);
    open_write = false;
    if (state_after_send != STATE_NONE)
      center->dispatch_event_external(read_handler);
  }

}

函数_try_send里比较关键的是:

  1. 当还有消息没有发送时, 就把该socket的 fd 添加到 EVENT_WRITABLE 事件中。
  2. 如果没有消息发送, 就把该 socket的 fd 的 EVENT_WRITABLE 事件监听删除

也就是当有发送请求时, 添加外部事件,并触发线程去处理发送事件。当外部事件一次可以完成发送消息的请求时,就不需要添加该fd对应的EVENT_WRITABLE 事件监听。当没有发送完消息时,就添加该fd的EVENT_WRITABLE 事件监听来触发内部事件去继续完成消息的发送。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值