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
- gearman 源码学习笔记3
- gearman 源码学习笔记1
- gearman 源码学习笔记2
- 【Gearman学习笔记】分布式处理入门
- 【Gearman学习笔记】持久化存储队列
- 【Gearman学习笔记】分布式处理入门
- gearman 0.32 安装笔记
- gearman 入门使用笔记
- gearman 入门使用笔记
- gearman 入门使用笔记
- Gearman入门学习
- gearman-client与gearman-worker的示例源码-C++版
- Gearman
- gearman
- Gearman
- Gearman
- gearman
- gearman
- SSA/ASS动态字幕详解
- p51 第二章 第11题 潘璠
- 从零创建MAVEN工程
- [c]队列queue
- 1-4
- gearman 源码学习笔记3
- Resource '/servers' does not exist
- Sublime text 3安装Emmet教程
- Dijkstra最短路径算法
- Android系统中添加一个产品----图文详解
- Stars (poj 2352 树状数组)
- 专业团队专业团队
- 提取某种颜色的像素点
- SQL Server2005快捷键