node.js的http.createServer过程深入解析(3)

代码中有个很重要的地方就是OnConnection函数,nodejs给listen函数设置了一个回调函数OnConnection,该函数在IO观察者里保存的文件描述符有连接到来时会被调用。OnConnection函数是在connection_wrap.cc定义的,tcp_wrapper继承了connection_wrap。下面我们先看一下uv_listen。该函数调用了uv_tcp_listen。该函数的核心代码如下。

if (listen(tcp->io_watcher.fd, backlog)) return UV__ERR(errno); // cb即OnConnection tcp->connection_cb = cb; tcp->flags |= UV_HANDLE_BOUND; // 有连接到来时的libuv层回调,覆盖了uv_stream_init时设置的值 tcp->io_watcher.cb = uv__server_io; // 注册事件 uv__io_start(tcp->loop, &tcp->io_watcher, POLLIN);

在libuv的poll IO阶段,epoll_wait会监听到到来的连接,然后调用uv__server_io。下面是该函数的核心代码。

// 继续注册事件,等待连接 uv__io_start(stream->loop, &stream->io_watcher, POLLIN); err = uv__accept(uv__stream_fd(stream)); // 保存连接对应的socket stream->accepted_fd = err; // 执行nodejs层回调 stream->connection_cb(stream, 0);

libuv会摘下一个连接,得到对应的socket。然后执行nodejs层的回调,这时候我们来看一下OnConnection的代码。

OnConnection(uv_stream_t* handle,int status) if (status == 0) { // 新建一个uv_tcp_t结构体 Local<Object> client_obj = WrapType::Instantiate(env, wrap_data, WrapType::SOCKET); WrapType* wrap; ASSIGN_OR_RETURN_UNWRAP(&wrap, client_obj); uv_stream_t* client_handle = reinterpret_cast<uv_stream_t*>(&wrap->handle_); // uv_accept返回0表示成功 if (uv_accept(handle, client_handle)) return; argv[1] = client_obj; } // 执行上层的回调,该回调是net.js设置的onconnection wrap_data->MakeCallback(env->onconnection_string(), arraysize(argv), argv);

OnConnection新建了一个uv_tcp_t结构体。代表这个连接。然后调用uv_accept。

int uv_accept(uv_stream_t* server, uv_stream_t* client) { ... // 新建的uv_tcp_t结构体关联accept_fd,注册读写事件 uv__stream_open(client, server->accepted_fd, UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); ... }

最后执行nodejs的回调。

function onconnection(err, clientHandle) { var handle = this; var self = handle.owner; if (err) { self.emit('error', errnoException(err, 'accept')); return; } if (self.maxConnections && self._connections >= self.maxConnections) { clientHandle.close(); return; } var socket = new Socket({ handle: clientHandle, allowHalfOpen: self.allowHalfOpen, pauseOnCreate: self.pauseOnConnect }); socket.readable = socket.writable = true; self._connections++; socket.server = self; socket._server = self; DTRACE_NET_SERVER_CONNECTION(socket); LTTNG_NET_SERVER_CONNECTION(socket); COUNTER_NET_SERVER_CONNECTION(socket); // 触发_http_server.js里设置的connectionListener回调 self.emit('connection', socket); }

listen函数总体的逻辑就是把socket设置为可监听,然后注册事件,等待连接的到来,连接到来的时候,调用accept获取新建立的连接,tcp_wrapper.cc的回调新建一个uv_tcp_t结构体,代表新的连接,然后设置可读写事件,并且设置回调为uv__stream_io,等待数据的到来。最后执行_http_server.js设置的回调connectionListener。至此,服务器启动并且接收连接的过程就完成了。接下来就是对用户数据的读写。当用户传来数据时,处理数据的函数是uv__stream_io。后面继续解析数据的读写。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/8084dbf09b11d985d7ebafa31580821e.html