前言
当客户端向 http server 发起 TCP 链接时, server 端会发起一系列的 callback 调用, 这是一个逆向调用的过程; 开始于 libuv, 终止于 js 代码里的 callback(promise then) 函数
如下图所示, http server 正向调用过程, 实际大部分的时间花在 net.js 上, 直到最下面的红框, 才调用了关键函数 createTCP()
- function createTCP() {
- // 绑定 tcp_wrap 模块, 调用 tcp constructor
- var TCP = process.binding('tcp_wrap').TCP;
- return new TCP();
- }
tcp_wrap 模块
我们看一下 tcpwrap::initialize() 的代码:
- void TCPWrap: :Initialize(Handle < Object > target, Handle < Value > unused, Handle < Context > context) {
- Environment * env = Environment: :GetCurrent(context);
- Local < FunctionTemplate > t = FunctionTemplate: :New(env - >isolate(), New);
- t - >SetClassName(FIXED_ONE_BYTE_STRING(env - >isolate(), "TCP"));
- t - >InstanceTemplate() - >SetInternalFieldCount(1);
- // Init properties
- t - >InstanceTemplate() - >Set(String: :NewFromUtf8(env - >isolate(), "reading"), Boolean: :New(env - >isolate(), false));
- t - >InstanceTemplate() - >Set(String: :NewFromUtf8(env - >isolate(), "owner"), Null(env - >isolate()));
- t - >InstanceTemplate() - >Set(String: :NewFromUtf8(env - >isolate(), "onread"), Null(env - >isolate()));
- t - >InstanceTemplate() - >Set(String: :NewFromUtf8(env - >isolate(), "onconnection"), Null(env - >isolate()));
- NODE_SET_PROTOTYPE_METHOD(t, "open", Open);
- NODE_SET_PROTOTYPE_METHOD(t, "bind", Bind);
- NODE_SET_PROTOTYPE_METHOD(t, "listen", Listen);
- NODE_SET_PROTOTYPE_METHOD(t, "getsockname", GetSockName);
- target - >Set(FIXED_ONE_BYTE_STRING(env - >isolate(), "TCP"), t - >GetFunction());
- }
- NODE_MODULE_CONTEXT_AWARE_BUILTIN(tcp_wrap, node: :TCPWrap: :Initialize)
利用 v8 engine 的 functionTemplate 创建一个 js 类
类的 constructor 是 TCP(),
类的 prototype 是 NODE_SET_PROTOTYPE_METHOD(),
类的属性是 t->InstanceTemplate()->Set().
在执行函数 createTCP() 调用 process.binding('tcp_wrap') 时, 其实会调用到下图在红框内, 可以看到参数 target 被设置成了 export 对象, 也就是说, tcp_wrap 模块真正导出的是 TCP 函数
Server.prototype._listen2
结合上图, 我们可以看到函数_listen2 中调用 createServerHandle() 返回了一个_handle 对象, 并且 self._handle.onconnection = onconnection, 这一步也非常重要
AsyncWrap 准备工作
AsyncWrap 和 Env 的代码截图:
准备工作及流程:
callBack 的逆向调用
前面都是铺垫, 这里才是正题
正向调用过程, 从 createServer() 开始, 到 listen() 结束, 为了创建一个基于 TCP 的 http server 了解 socket 流程的都知道, 到此为止, 创建工作实际已经完成, 剩下的就是等待客户 connect
而所有的 callback 执行的目的是对应用程序构造出一个 socket 的对象, 并且基于此对象完成面向连接的数据流读取操作
下图为调用流程:
First callback
TCP::Listen() 通过 libuv 提供的 uv_listen() 实现了 listen 异步调用, 并且指定了 callback 回调函数 TCPWrap::OnConnection()
OnConnection() 由 libuv 的 event loop 调用
在看 Nodejs Env.h 和 Env-inl.h 中可找到 PER_ISOLATE_STRING_PROPERTIES(v) 若干引用, 就像上面图所示, env->onconnection_string() 会返回 symbole onconnection
MakeCall 中, 通过 object()->Get() 获取 symbole 的对应函数
Other callback
net.js 中的 onconnection() 会被调用, 如下图所示:
两个要点, 一是创建了 socket 对象, 二是发出了 connection 时间
开发者调用 createServer() 时, 其实是在执行 new Server(), 而类 Server 中对 connection 之间有一个监听者, 那就是 connectionListener(), 也就是第三个 callback
通过前文, 我想后面的事情就不在赘述了
来源: https://www.cnblogs.com/peiyu1988/p/8443865.html