在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) {}
}