mysql中客户端连接server的三种方式

在mysqld_main函数的最后,通过下面的code来建立来自客户端的连接
mysqld_socket_acceptor->connection_event_loop();
  void connection_event_loop() {
    Connection_handler_manager *mgr =
        Connection_handler_manager::get_instance();
    while (!connection_events_loop_aborted()) {
      Channel_info *channel_info = m_listener->listen_for_connection_event();
      if (channel_info != NULL) mgr->process_new_connection(channel_info);
    }
  }

这里的listen_for_connection_event有三种实现分别是named_pipe/share_memory/socket_connetction.这三种分别实现在sql/Conn_handler 中,这里以socket_connetction的实现为例
Channel_info *Mysqld_socket_listener::listen_for_connection_event() {
#可以可以选择用poll还是select,为啥没有epoll呢?
#ifdef HAVE_POLL
  int retval = poll(&m_poll_info.m_fds[0], m_socket_map.size(), -1);
#else
  m_select_info.m_read_fds = m_select_info.m_client_fds;
  int retval = select((int)m_select_info.m_max_used_connection,
                      &m_select_info.m_read_fds, 0, 0, 0);
#endif
#retval小于零的异常情况 
  if (retval < 0 && socket_errno != SOCKET_EINTR) {
    /*
      select(2)/poll(2) failed on the listening port.
      There is not much details to report about the client,
      increment the server global status variable.
    */
    connection_errors_select++;
    if (!select_errors++ && !connection_events_loop_aborted())
      LogErr(ERROR_LEVEL, ER_CONN_SOCKET_SELECT_FAILED, socket_errno);
  }

  if (retval < 0 || connection_events_loop_aborted()) return NULL;

  /* Is this a new connection request ? */
#有一个新的连接,从这里知道可以同时有多个socket存在
  MYSQL_SOCKET listen_sock = MYSQL_INVALID_SOCKET;
  bool is_unix_socket = false;
#ifdef HAVE_POLL
  for (uint i = 0; i < m_socket_map.size(); ++i) {
    if (m_poll_info.m_fds[i].revents & POLLIN) {
      listen_sock = m_poll_info.m_pfs_fds[i];
      is_unix_socket = m_socket_map[listen_sock];
      break;
    }
  }
#else   // HAVE_POLL
  for (socket_map_iterator_t sock_map_iter = m_socket_map.begin();
       sock_map_iter != m_socket_map.end(); ++sock_map_iter) {
    if (FD_ISSET(mysql_socket_getfd(sock_map_iter->first),
                 &m_select_info.m_read_fds)) {
      listen_sock = sock_map_iter->first;
      is_unix_socket = sock_map_iter->second;
      break;
    }
  }
#endif  // HAVE_POLL

  MYSQL_SOCKET connect_sock;
  struct sockaddr_storage cAddr;
#同一个连接最多retry 10次
  for (uint retry = 0; retry < MAX_ACCEPT_RETRY; retry++) {
    socket_len_t length = sizeof(struct sockaddr_storage);
#通过accept得到socket,然后再通过mysql_socket_getfd得到fd
    connect_sock =
        mysql_socket_accept(key_socket_client_connection, listen_sock,
                            (struct sockaddr *)(&cAddr), &length);
    if (mysql_socket_getfd(connect_sock) != INVALID_SOCKET ||
        (socket_errno != SOCKET_EINTR && socket_errno != SOCKET_EAGAIN))
      break;
  }
#检查是否得到fd错误
  if (mysql_socket_getfd(connect_sock) == INVALID_SOCKET) {
    /*
      accept(2) failed on the listening port, after many retries.
      There is not much details to report about the client,
      increment the server global status variable.
    */
    connection_errors_accept++;
    if ((m_error_count++ & 255) == 0)  // This can happen often
      LogErr(ERROR_LEVEL, ER_CONN_SOCKET_ACCEPT_FAILED, strerror(errno));
    if (socket_errno == SOCKET_ENFILE || socket_errno == SOCKET_EMFILE)
      sleep(1);  // Give other threads some time
    return NULL;
  }



  Channel_info *channel_info = NULL;
#根据connect_sock 构建新的Channel_info_local_socket,并返回
  if (is_unix_socket)
    channel_info = new (std::nothrow) Channel_info_local_socket(connect_sock);
  else
    channel_info = new (std::nothrow) Channel_info_tcpip_socket(connect_sock);
  if (channel_info == NULL) {
    (void)mysql_socket_shutdown(connect_sock, SHUT_RDWR);
    (void)mysql_socket_close(connect_sock);
    connection_errors_internal++;
    return NULL;
  }

  return channel_info;
}
Channel_info_local_socket  会将connect_sock 保存在m_connect_sock中
class Channel_info_local_socket : public Channel_info {
  // connect socket object
  MYSQL_SOCKET m_connect_sock;

   /**
    Constructor that sets the connect socket.

    @param connect_socket set connect socket descriptor.
  */
  Channel_info_local_socket(MYSQL_SOCKET connect_socket)
      : m_connect_sock(connect_socket) {}
}

猜你喜欢

转载自blog.csdn.net/tiantao2012/article/details/81202461
今日推荐