MySQL 服务器监听客户端连接源码


在下面的代码有,有些结构体还不清楚,如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;

}

相关内容