手把手教你用nginx开发自己的服务器------利用nginx开发一个helloWorld程序(二)

现在我们正式开始编写nginx的helloWorld功能,该从哪下手呢?别急,我们在上一篇文章中提到了事件驱动对吧。nginx是怎么样事件驱动的呢?

我们来看看ngx_worker_process_cycle()这个函数的一部分

for ( ;; ) {

        if (ngx_exiting) {
            if (ngx_event_no_timers_left() == NGX_OK) {
                ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
                ngx_worker_process_exit(cycle);
            }
        }

        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle");

        ngx_process_events_and_timers(cycle);//重点关注一下
是不是很像上一篇文章中提到了epoll服务器的逻辑,OK,我们再来看下ngx_process_events_and_timers中是怎么处理事件的,看下这个部分
 (void) ngx_process_events(cycle, timer, flags);

完蛋了,是个回调函数,还是个宏定义,实体在哪呢?我们gdb看一下(nginx的gdb需要在auto/cc/conf文件中的ngx_compile_opt加上一个-g选项)

原来是ngx_epoll_process_events,出现了epoll字眼,越来越接近我们的要求了,现在我们启动nginx,然后gdb attach到worker进程上(一定要在ps -aux|grep nginx时看到哪个是worker进程哦,因为worker进程才是处理连接的,master进程是用来接收系统的一些消息和你输入的指令,然后通过signal的方式发送给worker进程的),在ngx_epoll_process_events上打个断电,然后用浏览器访问下我们的服务器。


是不是和上篇文章的epoll逻辑一样,循环处理每个epoll事件了,留意下rev,rev就是read event的意思,这个rev保存着整个事件的一些上下文信息,以及这个事件需要调用的handler(也就是函数),我们可以看到rev->handler事件就是ngx_event_accept函数,是不是又回到了echo服务器的基本逻辑,accept()?越来越清晰了,我们去ngx_event_accept这个函数里看一下:呃,一大堆各种判断用accept还是accept4等等乱七八糟的逻辑,好麻烦。。。别慌,我们只需要关注这个位置:

   log->data = NULL;
        log->handler = NULL;

        ls->handler(c);//重点关注

这个handler又是干嘛的(各种回调快要疯掉了好吗),别慌,我们gdb来看一下


ngx_http_init_connection,可以,初始化连接了开始,快接近事实的真相了,来,看下这个函数又在干嘛,呃。。。。又是一大坨,各种上下文,日志等东西的初始化,别急,我们只需要关注这一坨:

 rev = c->read;
    rev->handler = ngx_http_wait_request_handler;
    c->write->handler = ngx_http_empty_handler;

终于找到你了,原来读写事件的处理句柄是ngx_http_wait_request_handler,美滋滋,走进去一看,果然是处理各种消息的,想打印个helloWorld还不简单,直接在这个函数里加一行printf("helloWorld"),大功告成,保存再编译,咦,怎么没显示,不急不急,这不是你的问题,这是由于nginx以守护进程的形式在运行,所以标准输出没有定向到std中了,想测试这个helloworld,还是老老实实fopen一个文件,打印进去吧。

这里再说一下,rev->handler虽然挂上了,怎么调用的呢,回想下事件驱动机制,就是epoll_ctrl(add)嘛,然后去epoll循环里处理就好咯,回到ngx_http_init_connection中,看一下这个地方

 ngx_add_timer(rev, c->listening->post_accept_timeout);
    ngx_reusable_connection(c, 1);

    if (ngx_handle_read_event(rev, 0) != NGX_OK) {
        ngx_http_close_connection(c);
        return;

点进ngx_handler_read_event看一下,这里就是我们找了好久的epoll_ctrl(add)咯,美滋滋,原来这里就注册好了,等等,ngx_add_timer又是什么鬼,别慌,我来给你介绍下,ngx_add_timer是用来添加一个超时事件,nginx内部维护了一个事件红黑树,ngx_add_timer之后就会把这个时间和事件注册到红黑树里,只要时间一到,就会调用这个事件啦。所以,怪不得之前处理事件的函数叫ngx_process_events_and_timers嘛。

学会了写helloworld,在这里把功能替换成别的,也一样洒洒水啦,复杂的服务器逻辑,也就是把这个handler里面的功能写复杂,希望通过这两篇文章,能让你学会把握服务器开发最本质的几个地方,以后再去看其他的服务器代码,妈妈也再也不用担心啦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值