在下面的代码有,有些结构体还不清楚,如THD,st_vio,pollfd等。但可以看出MySQL使用Select模型来接收客户端的连接。而且也在网上查清,unix_sock是指同一机器中不同进程间的通信,如命名管道。而ip_sock指的是不同主机间的通信。void handle_connections_sockets(){ my_socket UNINIT_VAR(sock), UNINIT_VAR(new_sock); uint error_count=0; THD *thd; struct sockaddr_storage cAddr; int ip_flags=0,socket_flags=0,flags=0,retval; st_vio *vio_tmp;#ifdef HAVE_POLL int socket_count= 0; struct pollfd fds[2]; // for ip_sock and unix_sock#else fd_set readFDs,clientFDs; uint max_used_connection= (uint) (max(ip_sock,unix_sock)+1);#endif DBUG_ENTER("handle_connections_sockets"); #ifndef HAVE_POLL FD_ZERO(&clientFDs);#endif if (ip_sock != INVALID_SOCKET) {#ifdef HAVE_POLL fds[socket_count].fd= ip_sock; fds[socket_count].events= POLLIN; socket_count++;#else FD_SET(ip_sock,&clientFDs);#endif #ifdef HAVE_FCNTL ip_flags = fcntl(ip_sock, F_GETFL, 0);#endif }#ifdef HAVE_SYS_UN_H#ifdef HAVE_POLL fds[socket_count].fd= unix_sock; fds[socket_count].events= POLLIN; socket_count++;#else FD_SET(unix_sock,&clientFDs);#endif#ifdef HAVE_FCNTL socket_flags=fcntl(unix_sock, F_GETFL, 0);#endif#endif DBUG_PRINT("general",("Waiting for connections.")); MAYBE_BROKEN_SYSCALL; while (!abort_loop) {#ifdef HAVE_POLL retval= poll(fds, socket_count, -1);#else readFDs=clientFDs; retval= select((int) max_used_connection,&readFDs,0,0,0);//等待客户端连接,反回错误或有连接到来#endif if (retval < 0) { if (socket_errno != SOCKET_EINTR) { if (!select_errors++ && !abort_loop) /* purecov: inspected */ sql_print_error("mysqld: Got error %d from select",socket_errno); /* purecov: inspected */ } MAYBE_BROKEN_SYSCALL continue; } if (abort_loop) { MAYBE_BROKEN_SYSCALL; break; } /* Is this a new connection request ? */#ifdef HAVE_POLL for (int i= 0; i < socket_count; ++i) { if (fds[i].revents & POLLIN)//读取事件类型 { sock= fds[i].fd;#ifdef HAVE_FCNTL flags= fcntl(sock, F_GETFL, 0);#else flags= 0;#endif // HAVE_FCNTL break; } }#else // HAVE_POLL#ifdef HAVE_SYS_UN_H if (FD_ISSET(unix_sock,&readFDs)) { sock = unix_sock; flags= socket_flags; } else#endif // HAVE_SYS_UN_H { sock = ip_sock; flags= ip_flags; }#endif // HAVE_POLL #if !defined(NO_FCNTL_NONBLOCK) if (!(test_flags & TEST_BLOCKING)) {#if defined(O_NONBLOCK) fcntl(sock, F_SETFL, flags | O_NONBLOCK);//设置为非阻塞模式#elif defined(O_NDELAY) fcntl(sock, F_SETFL, flags | O_NDELAY);#endif }#endif /* NO_FCNTL_NONBLOCK */ for (uint retry=0; retry < MAX_ACCEPT_RETRY; retry++) { size_socket length= sizeof(struct sockaddr_storage); new_sock= accept(sock, (struct sockaddr *)(&cAddr),//接受连接,连接使用阻塞方式 &length); if (new_sock != INVALID_SOCKET || (socket_errno != SOCKET_EINTR && socket_errno != SOCKET_EAGAIN)) break; MAYBE_BROKEN_SYSCALL;#if !defined(NO_FCNTL_NONBLOCK) if (!(test_flags & TEST_BLOCKING)) { if (retry == MAX_ACCEPT_RETRY - 1) fcntl(sock, F_SETFL, flags); // Try without O_NONBLOCK }#endif }#if !defined(NO_FCNTL_NONBLOCK) if (!(test_flags & TEST_BLOCKING)) fcntl(sock, F_SETFL, flags);#endif if (new_sock == INVALID_SOCKET) { if ((error_count++ & 255) == 0) // This can happen often sql_perror("Error in accept"); MAYBE_BROKEN_SYSCALL; if (socket_errno == SOCKET_ENFILE || socket_errno == SOCKET_EMFILE) sleep(1); // Give other threads some time continue; } #ifdef HAVE_LIBWRAP { if (sock == ip_sock) { struct request_info req; signal(SIGCHLD, SIG_DFL); request_init(&req, RQ_DAEMON, libwrapName, RQ_FILE, new_sock, NULL); my_fromhost(&req); if (!my_hosts_access(&req))//判断主机是否具有访问权限 {//如果主机没有被赋予给予权限,则拒绝连接 /* This may be stupid but refuse() includes an exit(0) which we surely don"t want... clean_exit() - same stupid thing ... */ syslog(deny_severity, "refused connect from %s", my_eval_client(&req)); /* C++ sucks (the gibberish in front just translates the supplied sink function pointer in the req structure from a void (*sink)(); to a void(*sink)(int) if you omit the cast, the C++ compiler will cry... */ if (req.sink) ((void (*)(int))req.sink)(req.fd); (void) shutdown(new_sock, SHUT_RDWR);//关闭连接 (void) closesocket(new_sock); continue; } } }#endif /* HAVE_LIBWRAP */ { size_socket dummyLen; struct sockaddr_storage dummy; dummyLen = sizeof(dummy); if ( getsockname(new_sock,(struct sockaddr *)&dummy, (SOCKET_SIZE_TYPE *)&dummyLen) < 0 ) { sql_perror("Error on new connection socket"); (void) shutdown(new_sock, SHUT_RDWR); (void) closesocket(new_sock); continue; } } /* ** Don"t allow too many connections */ if (!(thd= new THD))//为该连接分配处理的结构,在以后用于给线程使用 { (void) shutdown(new_sock, SHUT_RDWR); (void) closesocket(new_sock); continue; } if (!(vio_tmp=vio_new(new_sock, sock == unix_sock ? VIO_TYPE_SOCKET : VIO_TYPE_TCPIP, sock == unix_sock ? VIO_LOCALHOST: 0)) || my_net_init(&thd->net,vio_tmp))//初始化网络 { /* Only delete the temporary vio if we didn"t already attach it to the NET object. The destructor in THD will delete any initialized net structure. */ if (vio_tmp && thd->net.vio != vio_tmp) vio_delete(vio_tmp); else { (void) shutdown(new_sock, SHUT_RDWR); (void) closesocket(new_sock); } delete thd; continue; } if (sock == unix_sock) thd->security_ctx->host=(char*) my_localhost; create_new_thread(thd);//准备为连接分配线程 } DBUG_VOID_RETURN;}MySQL 从接收连接到执行连接命令的一个源码流程MySQL新增一个连接源码相关资讯 MySQL教程
- 30分钟带你快速入门MySQL教程 (02月03日)
- MySQL教程:关于I/O内存方面的一些 (01月24日)
- CentOS上开启MySQL远程访问权限 (01/29/2013 10:58:40)
| - MySQL教程:关于checkpoint机制 (01月24日)
- MySQL::Sandbox (04/14/2013 08:03:38)
- 生产环境MySQL 5.5.x单机多实例配 (11/02/2012 21:02:36)
|
本文评论 查看全部评论 (0)