昨天我们聊到, C++ 连接层中的 TCP 物件被 JS 调用, 拿来注册事件及回调函数, 今天让我们继续看下去。
https://github.com/nodejs/node/blob/master/src/tcp_wrap.cc
env->SetProtoMethod(t, "open", Open);
env->SetProtoMethod(t, "bind", Bind);
env->SetProtoMethod(t, "listen", Listen);
env->SetProtoMethod(t, "connect", Connect);
env->SetProtoMethod(t, "bind6", Bind6);
env->SetProtoMethod(t, "connect6", Connect6);
env->SetProtoMethod(t, "getsockname",
GetSockOrPeerName<TCPWrap, uv_tcp_getsockname>);
env->SetProtoMethod(t, "getpeername",
GetSockOrPeerName<TCPWrap, uv_tcp_getpeername>);
env->SetProtoMethod(t, "setNoDelay", SetNoDelay);
env->SetProtoMethod(t, "setKeepAlive", SetKeepAlive);
在 TCP 的初始化就可看到这段程序码, SetProtoMethod 在 V8 中的作用是给物件天加上 prototype , 用 JS 的说法就是给物件加上 method 。
我们随意看一个 Listen method 在干嘛
void TCPWrap::Listen(const FunctionCallbackInfo<Value>& args) {
TCPWrap* wrap;
ASSIGN_OR_RETURN_UNWRAP(&wrap,
args.Holder(),
args.GetReturnValue().Set(UV_EBADF));
Environment* env = wrap->env();
int backlog;
if (!args[0]->Int32Value(env->context()).To(&backlog)) return;
int err = uv_listen(reinterpret_cast<uv_stream_t*>(&wrap->handle_),
backlog,
OnConnection);
args.GetReturnValue().Set(err);
}
跳过设定, 这段程序码的意思就是, 把回调函数 (这个方法的参数) 用 uv_listen 往下传。
所以看看 uv_listen 把参数(回调函数)传去哪了
int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
int err;
switch (stream->type) {
case UV_TCP:
err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
break;
case UV_NAMED_PIPE:
err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb);
break;
default:
err = UV_EINVAL;
}
if (err == 0)
uv__handle_start(stream);
return err;
}
假设类型是 TCP 直接查看 uv_tcp_listen
有两个选择
分别代表两个作业系统
我们只看 windows , 节省时间
int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
unsigned int i, simultaneous_accepts;
uv_tcp_accept_t* req;
int err;
assert(backlog > 0);
if (handle->flags & UV_HANDLE_LISTENING) {
handle->stream.serv.connection_cb = cb;
}
if (handle->flags & UV_HANDLE_READING) {
return WSAEISCONN;
}
if (handle->delayed_error) {
return handle->delayed_error;
}
if (!(handle->flags & UV_HANDLE_BOUND)) {
err = uv_tcp_try_bind(handle,
(const struct sockaddr*) &uv_addr_ip4_any_,
sizeof(uv_addr_ip4_any_),
0);
if (err)
return err;
if (handle->delayed_error)
return handle->delayed_error;
}
// 後略
略过检查与设定, 在uv_tcp_listen 中察看 uv_tcp_try_bind
static int uv_tcp_try_bind(uv_tcp_t* handle,
const struct sockaddr* addr,
unsigned int addrlen,
unsigned int flags) {
DWORD err;
int r;
if (handle->socket == INVALID_SOCKET) {
SOCKET sock;
/* Cannot set IPv6-only mode on non-IPv6 socket. */
if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
return ERROR_INVALID_PARAMETER;
sock = socket(addr->sa_family, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
return WSAGetLastError();
}
err = uv_tcp_set_socket(handle->loop, handle, sock, addr->sa_family, 0);
if (err) {
closesocket(sock);
return err;
}
}
// 後略
略过创建 socket 直接查看 uv_tcp_set_socket
static int uv_tcp_set_socket(uv_loop_t* loop,
uv_tcp_t* handle,
SOCKET socket,
int family,
int imported) {
DWORD yes = 1;
int non_ifs_lsp;
int err;
if (handle->socket != INVALID_SOCKET)
return UV_EBUSY;
/* Set the socket to nonblocking mode */
if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) {
return WSAGetLastError();
}
/* Make the socket non-inheritable */
if (!SetHandleInformation((HANDLE) socket, HANDLE_FLAG_INHERIT, 0))
return GetLastError();
/* Associate it with the I/O completion port. Use uv_handle_t pointer as
* completion key. */
if (CreateIoCompletionPort((HANDLE)socket,
loop->iocp,
(ULONG_PTR)socket,
0) == NULL) {
if (imported) {
handle->flags |= UV_HANDLE_EMULATE_IOCP;
} else {
return GetLastError();
}
}
// 後略
略过设定 , 终於看到了一个熟悉的 method CreateIoCompletionPort
这就是我前几天聊的 IOCP 注册方法, 至此我们对其中一种事件的注册有了大概的了解。
Node 注册事件的其中一种步骤
( 据说 unix 中会使用 epoll 不过我对这件事没做太多确认 )
明天开始介绍 libuv 如何 schedule 吧
明天见 !
<<: 用 Line LIFF APP 实现信箱验证绑定功能(1) - 取得 user email
>>: 07 | WordPress 空白间隔区块 Spacer Block
哈罗~ 来review一下, 之前提到维持权限时, 攻击者会建立後门或Rootkit, 并且会隐藏其...
加密前的资料在前几天我们都有拿到了!接着就是实作 AES-CBC 罗~ 流程如下图 关於 AES-C...
拇指法则 “拇指法则”是资深交互设计大神Steven Hoober在2013年对1300名手机用户的...
我在学生时代的大魔王-回圈loop 曾经写了一个无限回圈,让电脑执行时当机XD loop以英文直接来...
485. Max Consecutive Ones https://leetcode.com/pro...