code_tin

从头编写高性能服务程序9-多进程非阻塞epoll-prefork-hook
整个基础结构已经基本确定了 接下来做一些细节工作 首先把一些函数抽取出来. 例如prefork独立出来.socke...
扫描右侧二维码阅读全文
01
2010/02

从头编写高性能服务程序9-多进程非阻塞epoll-prefork-hook

整个基础结构已经基本确定了
接下来做一些细节工作
首先把一些函数抽取出来.
例如prefork独立出来.socket->bind->listen独立出来

这里我们引入一个新的思路
原先由统一的函数在epoll_wait之后对events里面的fd进行处理
但是每个fd可能需要处理的方式都不同.
怎么样针对不同的fd来调用特定的函数呢?

首先在epoll_event结构中有data成员
而data的定义如下
typedef union epoll_data { void *ptr; int fd; __uint32_t u32; __uint64_t u64; } epoll_data_t; struct epoll_event { __uint32_t events; /* Epoll events */ epoll_data_t data; /* User data variable */ };
可见既可以在events里面放data.fd
也可以使用data.ptr来指向一个指针
当fd有消息时内核将对应的ev变量塞入events数组的时候
如果我们只是用fd来指向注册的,那么获取数据的时候只能得到对应的fd
这样使用什么函数来处理这个fd就需要另行判断

那么如果使用ptr来指向一个结构
而结构内保存了fd以及处理这个fd所使用的函数指针
那当我们得到events数组内的事件时
就可以直接调用ptr指向的函数指针了.
这就类似Nginx中的hook函数.
在Nginx中几乎任何一种事件都会绑定其处理函数
而由模块实现距离的函数,然后在hook上去.

那么下面的代码我们就模拟这个方法:
我们建立一个数据结构来保存每个fd以及对应的处理函数
struct event_handle{ int fd; int (* handle)(int fd); };
handle_hook是我们为每个fd注册的处理函数
当accept获得新的accept_fd之后
我们使用ev_handles[accept_handles].handle = handle_hook
来将对应的函数注册到对应的events内
在fd得到通知的时候
使用(*current_handle)(current_fd)来进行处理

#include #include #include #include #include #include #include #include #include #include #include int create_listen_fd(int port){ int listen_fd; struct sockaddr_in my_addr; if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){ perror("create socket error"); exit(1); } int flag; if (setsockopt(listen_fd,SOL_SOCKET,SO_REUSEADDR ,(char *)&flag,sizeof(flag)) == -1){ perror("setsockopt error"); } int flags = fcntl(listen_fd, F_GETFL, 0); fcntl(listen_fd, F_SETFL, flags|O_NONBLOCK); my_addr.sin_family = AF_INET; my_addr.sin_port = htons(port); my_addr.sin_addr.s_addr = INADDR_ANY; bzero(&(my_addr.sin_zero), 8); if (bind(listen_fd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr_in)) == -1) { perror("bind error"); exit(1); } if (listen(listen_fd,1) == -1){ perror("listen error"); exit(1); } return listen_fd; } int create_accept_fd(int listen_fd){ int addr_len = sizeof( struct sockaddr_in ); struct sockaddr_in remote_addr; int accept_fd = accept( listen_fd, (struct sockaddr *)&remote_addr, &addr_len ); int flags = fcntl(accept_fd, F_GETFL, 0); fcntl(accept_fd, F_SETFL, flags|O_NONBLOCK); return accept_fd; } int fork_process(int process_num){ int i; int pid=-1; for(i = 0; i < process_num; i++){ if(pid != 0){ pid = fork(); } } return pid; } int handle_normal(int socket_fd){ char in_buf[1024]; memset(in_buf, 0, 1024); int recv_num = recv( socket_fd, &in_buf, 1024, 0 ); if( recv_num ==0 ){ close(socket_fd); printf("ProcessID:%d,EPOLLIN,fd:%d,closed\n", getpid(), socket_fd); } else{ printf("ProcessID:%d,EPOLLIN,fd:%d,recv:%s\n", getpid(), socket_fd, in_buf); } return recv_num; } int handle_hook(int socket_fd){ char in_buf[1024]; memset(in_buf, 0, 1024); int recv_num = recv( socket_fd, &in_buf, 1024, 0 ); if( recv_num ==0 ){ close(socket_fd); printf("ProcessID:%d,EPOLLIN,fd:%d,closed\n", getpid(), socket_fd); } else{ printf("ProcessID:%d,EPOLLIN,fd:%d,recv_num:%d;recv:", getpid(), socket_fd, recv_num); for (int i = 0; ihandle; int current_fd = ((EH)(events[i].data.ptr))->fd; if( (*current_handle)(current_fd) == 0){ accept_handles--; } } else if(events[i].events&EPOLLOUT){ //need add write event process } } } } else{ //manager the process int child_process_status; wait(&child_process_status); } return 0; }

Last modification:November 26th, 2018 at 04:16 pm
If you think my article is useful to you, please feel free to appreciate

One comment

  1. hoterran

    epoll_data里不是有fd了么?handle还fd干嘛?

    current_fd = events[i].data.fd 即可

Leave a Comment