gearman 源码学习笔记3

来源:互联网 发布:centos安装wine 编辑:程序博客网 时间:2024/05/22 05:24

这次说一把gearman的网络模块,gearman是利用libevent高性能网络库实现网络功能的。

首先看

 gearmand->ret= _listen_init(gearmand);    if (gearmand->ret != GEARMAND_SUCCESS)    {      return gearmand->ret;    }
gearman在_listen_init
<pre name="code" class="cpp">static gearmand_error_t _listen_init(gearmand_st *gearmand){  for (uint32_t x= 0; x < gearmand->_port_list.size(); ++x)  {    struct addrinfo hints;    struct addrinfo *addrinfo= NULL;    gearmand_port_st *port= &gearmand->_port_list[x];    memset(&hints, 0, sizeof(struct addrinfo));    hints.ai_flags= AI_PASSIVE;    hints.ai_socktype= SOCK_STREAM;    {      int ret= getaddrinfo(gearmand->host, port->port, &hints, &addrinfo);      if (ret != 0)      {        char buffer[1024];        int length= snprintf(buffer, sizeof(buffer), "%s:%s", gearmand->host ? gearmand->host : "<any>", port->port);        if (length <= 0 or size_t(length) >= sizeof(buffer))        {          buffer[0]= 0;        }        if (addrinfo)        {          freeaddrinfo(addrinfo);        }        return gearmand_gai_error(buffer, ret);      }    }    std::set<host_port_t> unique_hosts;    for (struct addrinfo *addrinfo_next= addrinfo; addrinfo_next != NULL;         addrinfo_next= addrinfo_next->ai_next)    {      char host[NI_MAXHOST];      {        int ret= getnameinfo(addrinfo_next->ai_addr, addrinfo_next->ai_addrlen, host,                             NI_MAXHOST, port->port, NI_MAXSERV,                             NI_NUMERICHOST | NI_NUMERICSERV);        if (ret != 0)        {          gearmand_gai_error("getaddrinfo", ret);          strncpy(host, "-", sizeof(host));          strncpy(port->port, "-", sizeof(port->port));        }      }      std::string host_string(host);      std::string port_string(port->port);      host_port_t check= std::make_pair(host_string, port_string);      if (unique_hosts.find(check) != unique_hosts.end())      {        gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "Already listening on %s:%s", host, port->port);        continue;      }      unique_hosts.insert(check);      gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "Trying to listen on %s:%s", host, port->port);      /*        @note logic for this pulled from Drizzle.        Sometimes the port is not released fast enough when stopping and        restarting the server. This happens quite often with the test suite        on busy Linux systems. Retry to bind the address at these intervals:        Sleep intervals: 1, 2, 4,  6,  9, 13, 17, 22, ...        Retry at second: 1, 3, 7, 13, 22, 35, 52, 74, ...        Limit the sequence by drizzled_bind_timeout.      */      uint32_t waited;      uint32_t this_wait;      uint32_t retry;      int ret= -1;      int fd;      for (waited= 0, retry= 1; ; retry++, waited+= this_wait)      {        {           gearmand_error_t socket_ret;          if (gearmand_failed(socket_ret= set_socket(gearmand, fd, addrinfo_next)))          {            gearmand_sockfd_close(fd);            freeaddrinfo(addrinfo);            return socket_ret;          }        }        errno= 0;        if ((ret= bind(fd, addrinfo_next->ai_addr, addrinfo_next->ai_addrlen)) == 0)        {          // Success          break;        }        // Protect our error        ret= errno;        gearmand_sockfd_close(fd);                if (waited >= bind_timeout)        {          freeaddrinfo(addrinfo);          return gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "Timeout occured when calling bind() for %s:%s", host, port->port);        }        if (ret != EADDRINUSE)        {          freeaddrinfo(addrinfo);          return gearmand_perror(ret, "bind");        }        this_wait= retry * retry / 3 + 1;        // We are in single user threads, so strerror() is fine.        gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "Retrying bind(%s) on %s:%s %u + %u >= %u",                            strerror(ret), host, port->port,                           waited, this_wait, bind_timeout);        struct timespec requested;        requested.tv_sec= this_wait;        requested.tv_nsec= 0;        nanosleep(&requested, NULL);      }      if (listen(fd, gearmand->backlog) == -1)      {        gearmand_perror(errno, "listen");        gearmand_sockfd_close(fd);        freeaddrinfo(addrinfo);        return GEARMAND_ERRNO;      }      // Scoping note for eventual transformation      {        int* fd_list= (int *)realloc(port->listen_fd, sizeof(int) * (port->listen_count + 1));        if (fd_list == NULL)        {          gearmand_perror(errno, "realloc");          gearmand_sockfd_close(fd);          freeaddrinfo(addrinfo);          return GEARMAND_ERRNO;        }        port->listen_fd= fd_list;      }      port->listen_fd[port->listen_count]= fd;      port->listen_count++;      gearmand_log_info(GEARMAN_DEFAULT_LOG_PARAM, "Listening on %s:%s (%d)", host, port->port, fd);    }    freeaddrinfo(addrinfo);    /* Report last socket() error if we couldn't find an address to bind. */    if (port->listen_fd == NULL)    {      return gearmand_log_fatal(GEARMAN_DEFAULT_LOG_PARAM, "Could not bind/listen to any addresses");    }    assert(port->listen_event == NULL);    port->listen_event= (struct event *)malloc(sizeof(struct event) * port->listen_count); // libevent POD    if (port->listen_event == NULL)    {      return gearmand_merror("malloc(sizeof(struct event) * port->listen_count)", struct event, port->listen_count);    }    for (uint32_t y= 0; y < port->listen_count; ++y)    {      event_set(&(port->listen_event[y]), port->listen_fd[y], EV_READ | EV_PERSIST, _listen_event, port);      if (event_base_set(gearmand->base, &(port->listen_event[y])) == -1)      {        return gearmand_perror(errno, "event_base_set()");      }    }  }  return GEARMAND_SUCCESS;}


具体在socket_ret= set_socket(gearmand, fd, addrinfo_next) 初始化套接字

然后 bind listen(fd, gearmand->backlog) 

最终将 fd注册给libevent event_base_set(gearmand->base, &(port->listen_event[y])

当发生 accept事件时(其实就是tcp的三次握手)或触发_listen_event 处理事件

请看

static void _listen_event(int event_fd, short events __attribute__ ((unused)), void *arg){  gearmand_port_st *port= (gearmand_port_st *)arg;  struct sockaddr sa;  socklen_t sa_len= sizeof(sa);#if defined(HAVE_ACCEPT4) && HAVE_ACCEPT4  int fd= accept4(event_fd, &sa, &sa_len, SOCK_NONBLOCK); //  SOCK_NONBLOCK);#else  int fd= accept(event_fd, &sa, &sa_len);#endif  if (fd == -1)  {    int local_error= errno;    switch (local_error)    {    case EINTR:      return;    case ECONNABORTED:    case EMFILE:      gearmand_perror(local_error, "accept");      return;    default:      break;    }    _clear_events(Gearmand());    Gearmand()->ret= gearmand_perror(local_error, "accept");    return;  }  gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "accept() fd:%d", fd);  /*     Since this is numeric, it should never fail. Even if it did we don't want to really error from it.  */  char host[NI_MAXHOST];  char port_str[NI_MAXSERV];  int error= getnameinfo(&sa, sa_len, host, NI_MAXHOST, port_str, NI_MAXSERV,                         NI_NUMERICHOST | NI_NUMERICSERV);  if (error != 0)  {    gearmand_gai_error("getnameinfo", error);    strncpy(host, "-", sizeof(host));    strncpy(port_str, "-", sizeof(port_str));  }  gearmand_log_info(GEARMAN_DEFAULT_LOG_PARAM, "Accepted connection from %s:%s", host, port_str);  {    int flags= 1;    if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags)) == -1)    {      gearmand_log_perror(GEARMAN_DEFAULT_LOG_PARAM, errno, "%s:%s setsockopt(SO_KEEPALIVE)", host, port_str);    }  }  gearmand_error_t ret= gearmand_con_create(Gearmand(), fd, host, port_str, port);  if (ret == GEARMAND_MEMORY_ALLOCATION_FAILURE)  {    gearmand_sockfd_close(fd);    return;  }  else if (ret != GEARMAND_SUCCESS)  {    Gearmand()->ret= ret;    _clear_events(Gearmand());  }}

在gearmand_con_create里有比较复杂的逻辑包括 实现创建连接 roundrobbin 选择工作线程 已经pip通知工作线程。下班啦 下回再写啦。






0 0
原创粉丝点击