这次详细分析一下各个模型的connect调用,对于WEB服务器,必然调用accept,但也少不了connect,一般用于连接后端WEB服务器或者邮件服务器
在调用 rc = connect(s, pc->sockaddr, pc->socklen);之后NGX会调用 ngx_add_event来注册connect的事件 ngx_add_event是一个宏对于不同的网络模型会有对应的具体函数, 对于IOCP来说是ngx_iocp_add_event 对于SELECT来说是ngx_select_add_event 对于EPOLL来说是ngx_epoll_add_event
connect的返回值,不同操作系统返回值略有差别。先看看select 模型的处理流程 以http_up_stream模块为例。 ngx_http_upstream_connect函数里面调用ngx_event_connect_peer,将结构体ngx_peer_connection_s传递进去。
ngx_event_connect_peer执行初始化socket,设置收/发缓存,绑定等初始化工作。 r然后调用connect,如果返回NGX_OK,那么最后调用ngx_http_upstream_send_request发送请求。 如果connect返回-1,还要判断errno,如果不是EWOULDBLOCK类似的错误码直接返回。如果是的话则会向select模型中添加读,写句柄。调用的即前面提到的 ngx_select_add_event, ngx_select_add_event 会把读写FD添加到全局的master_read_fd_set,master_write_fd_set读写符号集里面。这是select的标准动作。剩下的事情则交给select模型。 而循环检查读写状态的是ngx_select_process_events,其关键代码如下:
ready = select(max_fd 1, &work_read_fd_set, &work_write_fd_set, NULL, tp);
这里发现读/写 符号就绪以后,就会调用ngx_post_event(ev, queue);把代表单次I/O上下文的ev对象放入全局的队列中,实际上是2个队列ngx_posted_accept_events,ngx_posted_events。 而对ev-handle的执行则是在ngx_worker_process_cycle->ngx_process_events_and_timers->ngx_event_process_posted函数里面,其唯一的调用就是ev->handler(ev); 实际上调用的是ngx_http_upstream_send_request_handler,在这个函数中经过一些处理之后调用ngx_http_upstream_send_request。 如果返回的是NGX_OK,则直接调用ngx_http_upstream_send_request
如果connect处于等待状态,还会调用ngx_event_add_timer,添加一个超时对象。一旦此次connect超时,则会在ngx_process_events_and_timers中触发相应的超时处理函数。 在回头看看ngx_http_upstream_connect函数,有2个参数 ngx_http_request_t和ngx_http_upstream_t 在简单处理了时间方面的记录以后就调用ngx_event_connect_peer,如果返回NGX_ERROR,表示当前socket出现异常,调用ngx_http_upstream_finalize_request关闭这个socket。
如果返回NGX_DECLINED,表示连接对象连接失败,则调用ngx_http_upstream_next继续执行下一个反向代理目标。
如果connect立即成功或者进入异步等待状态,设置读写Handle等一系列参数 c = u->peer.connection; 一旦异步connect成功返回,则会调用这些读写handle来执行读写操作。 最后如果是异步状态,调用下面的代码
if (rc == NGX_AGAIN) { 对这个connect建立一个定时器来监控connect的超时,一旦超时则会触发相应的处理函数来撤销这个异步connect。 如果connect立即成功,则调用ngx_http_upstream_send_request,开始向反向代理目标发送http request。
|
|
来自: waitingnothing > 《Nginx》