本文共 4103 字,大约阅读时间需要 13 分钟。
在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) {}}
转载地址:http://pinmi.baihongyu.com/