Chinaunix首页 | 论坛 | 博客
  • 博客访问: 46269
  • 博文数量: 13
  • 博客积分: 1857
  • 博客等级: 上尉
  • 技术积分: 100
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-05 10:56
文章分类
文章存档

2011年(10)

2010年(3)

最近访客

分类: C/C++

2010-08-25 11:10:44

从头编写高性能服务程序(三)

从头编写高性能服务程序12-区分读写事件

前一个版本很重要的BUG
就是sendfile在发送大文件的时候会发送不完整
这个bug指出了另一需求
就是需要用到EPOLLOUT事件

前面版本我们事件处理都是在EPOLLIN中进行
当有accept_fd数据进来之后
我们判断指令的内容
再直接进行数据的处理

我们更换一种方式
当accept_fd获取到数据之后
解析数据.
当需要输出的时候,将accept_fd的事件变为EPOLLOUT

这样一种fd会有两种状态
接受指令状态以及输出数据状态
慢慢的.我们会发现这个程序越来越像Nginx或者Lighttpd了
因为一个连接会有不同的状态
事件+状态机就是Nginx以及Lighttpd高效的原因
将一个链接分成不同的生命周期然后处理

经过进化
我们的event_handle结构拥有了读写两种hook钩子

typedef struct event_handle{
    ...
    int ( * read_handle  )( struct event_handle * ev );
    int ( * write_handle )( struct event_handle * ev );
    ...
}

而我们在针对的处理过程中
初始化时会针对不同的事件挂上不同的钩子函数

int init_evhandle(...){
    ...
    ev->read_handle = r_handle;
    ev->write_handle = w_handle;
    ...
}

接着在事件发生时调用不同的钩子函数

else if( events[i].events&EPOLLIN ){
    EVENT_HANDLE current_handle = ( ( EH )( events[i].data.ptr ) )->read_handle;
    ...
}
else if( events[i].events&EPOLLOUT ){
    EVENT_HANDLE current_handle = ( ( EH )( events[i].data.ptr ) )->write_handle;
    ...
}

当分析完指令的时候
将fd变为EPOLLOUT

int parse_request(
    ...
    ev_temp.data.ptr = ev;
    ev_temp.events = EPOLLOUT|EPOLLET;
    epoll_ctl( ev->epoll_fd, EPOLL_CTL_MOD, ev->socket_fd, &ev_temp );
    ...
}

加入这些处理之后
代码越来越长了
我们还需要加很多东西
比如进程管理,等等
这之后会发现一个mini的nginx骨架或者lighttpd骨架出现了

下载:
  1. #include <sys/socket.h>
  2. #include <sys/wait.h>
  3. #include <netinet/in.h>
  4. #include <netinet/tcp.h>
  5. #include <sys/epoll.h>
  6. #include <sys/sendfile.h> 
  7. #include <sys/stat.h>
  8. #include <unistd.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <strings.h>
  13. #include <fcntl.h>
  14. #include <errno.h>
  15. #define HANDLE_INFO   1
  16. #define HANDLE_SEND   2
  17. #define HANDLE_DEL    3
  18. #define HANDLE_CLOSE  4
  19. #define MAX_REQLEN          1024
  20. #define MAX_PROCESS_CONN    3
  21. #define FIN_CHAR            0x00
  22. #define SUCCESS  0
  23. #define ERROR   -1
  24. typedef struct event_handle{
  25.     int socket_fd;
  26.     int file_fd;
  27.     int file_pos;
  28.     int epoll_fd;
  29.     char request[MAX_REQLEN];
  30.     int request_len;
  31.     int ( * read_handle )( struct event_handle * ev );
  32.     int ( * write_handle )( struct event_handle * ev );
  33.     int handle_method;
  34. } EV,* EH;
  35. typedef int ( * EVENT_HANDLE )( struct event_handle * ev );
  36. int create_listen_fd( int port ){
  37.     int listen_fd;
  38.     struct sockaddr_in my_addr;
  39.     if( ( listen_fd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 ){
  40.         perror( "create socket error" );
  41.         exit( 1 );
  42.     }
  43.     int flag;
  44.     int olen = sizeof(int);
  45.     if( setsockopt( listen_fd, SOL_SOCKET, SO_REUSEADDR
  46.                         , (const void *)&flag, olen ) == -1 ){
  47.         perror( "setsockopt error" );
  48.     }
  49.     flag = 5;
  50.     if( setsockopt( listen_fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &flag, olen ) == -1 ){
  51.         perror( "setsockopt error" );
  52.     }
  53.     flag = 1;
  54.     if( setsockopt( listen_fd, IPPROTO_TCP, TCP_CORK, &flag, olen ) == -1 ){
  55.         perror( "setsockopt error" );
  56.     }
  57.     int flags = fcntl( listen_fd, F_GETFL, 0 );
  58.     fcntl( listen_fd, F_SETFL, flags|O_NONBLOCK );
  59.     my_addr.sin_family = AF_INET;
  60.     my_addr.sin_port = htons( port );
  61.     my_addr.sin_addr.s_addr = INADDR_ANY;
  62.     bzero( &( my_addr.sin_zero ), 8 );
  63.     if( bind( listen_fd, ( struct sockaddr * )&my_addr,
  64.     sizeof( struct sockaddr_in ) ) == -1 ) {
  65.         perror( "bind error" );
  66.         exit( 1 );
  67.     }
  68.     if( listen( listen_fd, 1 ) == -1 ){
  69.         perror( "listen error" );
  70.         exit( 1 );
  71.     }
  72.     return listen_fd;
  73. }
  74. int create_accept_fd( int listen_fd ){
  75.     int addr_len = sizeof( struct sockaddr_in );
  76.     struct sockaddr_in remote_addr;
  77.     int accept_fd = accept( listen_fd,
  78.         ( struct sockaddr * )&remote_addr, &addr_len );
  79.     int flags = fcntl( accept_fd, F_GETFL, 0 );
  80.     fcntl( accept_fd, F_SETFL, flags|O_NONBLOCK );
  81.     return accept_fd;
  82. }
  83. int fork_process( int process_num ){
  84.     int i;
  85.     int pid=-1;
  86.     for( i = 0; i < process_num; i++ ){
  87.         if( pid != 0 ){
  88.             pid = fork();
  89.         }
  90.     }
  91.     return pid;
  92. }
  93. int init_evhandle(EH ev,int socket_fd,int epoll_fd,EVENT_HANDLE r_handle,EVENT_HANDLE w_handle){
  94.     ev->epoll_fd = epoll_fd;
  95.     ev->socket_fd = socket_fd;
  96.     ev->read_handle = r_handle;
  97.     ev->write_handle = w_handle;
  98.     ev->file_pos = 0;
  99.     ev->request_len = 0;
  100.     ev->handle_method = 0;
  101.     memset( ev->request, 0, 1024 );
  102. }
  103. //accept->accept_queue->request->request_queue->output->output_queue
  104. //multi process sendfile
  105. int parse_request(EH ev){
  106.     ev->request_len--;
  107.     *( ev->request + ev->request_len - 1 ) = 0x00;
  108.     int i;
  109.     for( i=0; i<ev->request_len; i++ ){
  110.         if( ev->request[i] == ':' ){
  111.             ev->request_len = ev->request_len-i-1;
  112.             char temp[MAX_REQLEN];
  113.             memcpy( temp, ev->request, i );
  114.             ev->handle_method = atoi( temp );
  115.             memcpy( temp, ev->request+i+1, ev->request_len );
  116.             memcpy( ev->request, temp, ev->request_len );
  117.             break;
  118.         }
  119.     }
  120.     //handle_request( ev );
  121.     //register to epoll EPOLLOUT
  122.    
  123.     struct epoll_event ev_temp;
  124.     ev_temp.data.ptr = ev;
  125.     ev_temp.events = EPOLLOUT|EPOLLET;
  126.     epoll_ctl( ev->epoll_fd, EPOLL_CTL_MOD, ev->socket_fd, &ev_temp );
  127.     return SUCCESS;
  128. }
  129. int handle_request(EH ev){
  130.     struct stat file_info;
  131.     switch( ev->handle_method ){
  132.         case HANDLE_INFO:
  133.             ev->file_fd = open( ev->request, O_RDONLY );
  134.             if( ev->file_fd == -1 ){
  135.                 send( ev->socket_fd, "open file failed\n", strlen("open file failed\n"), 0 );
  136.                 return -1;
  137.             }
  138.             fstat(ev->file_fd, &file_info);
  139.             char info[MAX_REQLEN];
  140.             sprintf(info,"file len:%d\n",file_info.st_size);
  141.             send( ev->socket_fd, info, strlen( info ), 0 );
  142.             break;
  143.         case HANDLE_SEND:
  144.             ev->file_fd = open( ev->request, O_RDONLY );
  145.             if( ev->file_fd == -1 ){
  146.                 send( ev->socket_fd, "open file failed\n", strlen("open file failed\n"), 0 );
  147.                 return -1;
  148.             }
  149.             fstat(ev->file_fd, &file_info);
  150.             sendfile( ev->socket_fd, ev->file_fd, 0, file_info.st_size );
  151.             break;
  152.         case HANDLE_DEL:
  153.             break;
  154.         case HANDLE_CLOSE:
  155.             break;
  156.     }
  157.     finish_request( ev );
  158.     return SUCCESS;
  159. }
  160. int finish_request(EH ev){
  161.     close(ev->socket_fd);
  162.     close(ev->file_fd);
  163.     ev->handle_method = -1;
  164.     clean_request( ev );
  165.     return SUCCESS;
  166. }
  167. int clean_request(EH ev){
  168.     memset( ev->request, 0, MAX_REQLEN );
  169.     ev->request_len = 0;
  170. }
  171. int read_hook_v2( EH ev ){
  172.     char in_buf[MAX_REQLEN];
  173.     memset( in_buf, 0, MAX_REQLEN );
  174.     int recv_num = recv( ev->socket_fd, &in_buf, MAX_REQLEN, 0 );
  175.     if( recv_num ==0 ){
  176.         close( ev->socket_fd );
  177.         return ERROR;
  178.     }
  179.     else{
  180.         //check ifoverflow
  181.         if( ev->request_len > MAX_REQLEN-recv_num ){
  182.             close( ev->socket_fd );
  183.             clean_request( ev );
  184.         }
  185.         memcpy( ev->request + ev->request_len, in_buf, recv_num );
  186.         ev->request_len += recv_num;
  187.         if( recv_num == 2 && ( !memcmp( &in_buf[recv_num-2], "\r\n", 2 ) ) ){
  188.             parse_request(ev);
  189.         }
  190.     }
  191.     return recv_num;
  192. }
  193. int write_hook_v1( EH ev ){
  194.     struct stat file_info;
  195.     ev->file_fd = open( ev->request, O_RDONLY );
  196.     if( ev->file_fd == ERROR ){
  197.         send( ev->socket_fd, "open file failed\n", strlen("open file failed\n"), 0 );
  198.         return ERROR;
  199.     }
  200.     fstat(ev->file_fd, &file_info);
  201.     int write_num;
  202.     while(1){
  203.         write_num = sendfile( ev->socket_fd, ev->file_fd, (off_t *)&ev->file_pos, 10240 );
  204.         ev->file_pos += write_num;
  205.         if( write_num == ERROR ){
  206.             if( errno == EAGAIN ){
  207.                 break;
  208.             }
  209.         }
  210.         else if( write_num == 0 ){
  211.             printf( "writed:%d\n", ev->file_pos );
  212.             //finish_request( ev );
  213.             break;
  214.         }
  215.     }
  216.     return SUCCESS;
  217. }
  218. int main(){
  219.     int listen_fd = create_listen_fd( 3389 );
  220.     int pid = fork_process( 3 );
  221.     if( pid == 0 ){
  222.         int accept_handles = 0;
  223.         struct epoll_event ev, events[20];
  224.         int epfd = epoll_create( 256 );
  225.         int ev_s = 0;
  226.        
  227.         ev.data.fd = listen_fd;
  228.         ev.events = EPOLLIN|EPOLLET;
  229.         epoll_ctl( epfd, EPOLL_CTL_ADD, listen_fd, &ev );
  230.         struct event_handle ev_handles[256];
  231.         for( ;; ){
  232.             ev_s = epoll_wait( epfd, events, 20, 500 );
  233.             int i = 0;
  234.             for( i = 0; i<ev_s; i++ ){
  235.                 if( events[i].data.fd == listen_fd ){
  236.                     if( accept_handles < MAX_PROCESS_CONN ){
  237.                         accept_handles++;
  238.                         int accept_fd = create_accept_fd( listen_fd );
  239.                         init_evhandle(&ev_handles[accept_handles],accept_fd,epfd,read_hook_v2,write_hook_v1);
  240.                         ev.data.ptr = &ev_handles[accept_handles];
  241.                         ev.events = EPOLLIN|EPOLLET;
  242.                         epoll_ctl( epfd, EPOLL_CTL_ADD, accept_fd, &ev );
  243.                     }
  244.                 }
  245.                 else if( events[i].events&EPOLLIN ){
  246.                     EVENT_HANDLE current_handle = ( ( EH )( events[i].data.ptr ) )->read_handle;
  247.                     EH current_event = ( EH )( events[i].data.ptr );
  248.                     ( *current_handle )( current_event );
  249.                 }
  250.                 else if( events[i].events&EPOLLOUT ){
  251.                     EVENT_HANDLE current_handle = ( ( EH )( events[i].data.ptr ) )->write_handle;
  252.                     EH current_event = ( EH )( events[i].data.ptr );
  253.                     if( ( *current_handle )( current_event )  == 0 ){ 
  254.                         accept_handles--;
  255.                     }
  256.                 }
  257.             }
  258.         }
  259.     }
  260.     else{
  261.         //manager the process
  262.         int child_process_status;
  263.         wait( &child_process_status );
  264.     }
  265.    
  266.     return SUCCESS;
  267. }
[转]http://blog.chinaunix.net/u/6889/showart.php?id=2296858
阅读(1403) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-08-28 08:55:42

Download More than 1000 free IT eBooks: http://free-ebooks.appspot.com