美文网首页
Nodejs net 模块学习及源码阅读

Nodejs net 模块学习及源码阅读

作者: ithankzc | 来源:发表于2021-09-06 22:03 被阅读0次

Node 版本

10.24.1

引入模块

const net = require('net');

创建 Socket 服务

方式一

net.createServer([options][,connectionlistener]);

也可以用方式二

new net.Server(options, connectionListener);

在 net.js 源码里面,createServer 其实也是做了 new Server 的的操作

function createServer(options, connectionListener) {
  return new Server(options, connectionListener);
}

这里 server 返回值是 net.Server,继承了 Nodejs 的事件触发器。

net.Server 有如下事件

  • connection
  • listening
  • error
  • close

connection

当客户端 连接服务器的时候,会触发 connection 事件

服务端

const server = net.createServer((socket) => {
    socket.on('data', (data) => {
      console.log("receive_data:" + data);
      socket.write(data);
    });
});

server.on('connection', (socket) => {
  socket.write('create connect');
});

server.listen(8686, () => {
    console.log(8686);
});
server.on('listening', () => {
   console.log('listening');
});

客户端发起请求

➜  ~ telnet 127.0.0.1 8686
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
create connect // 这里是建立连接后服务器返回的结果

在这里,我们可以更深层次的了解服务端连接事件触发的过程
当客户端与服务端建立起连接是,Nodejs 在系统层面会调度 onconnection 方法


image.png

onconnection 方法主要做了两件事情

  1. 创建 socket
  2. 触发 connection 事件,并将 socket 对象作为参数
  ......
  var socket = new Socket({
    handle: clientHandle,
    allowHalfOpen: self.allowHalfOpen,
    pauseOnCreate: self.pauseOnConnect,
    readable: true,
    writable: true
  });

  self._connections++;
  socket.server = self;
  socket._server = self;

  DTRACE_NET_SERVER_CONNECTION(socket);
  ;
  self.emit('connection', socket); //  触发 connection 事件

创建 socket 对象有一部分很重要,是关于服务端接受接收客户端处理

 stream.Duplex.call(this, options);

这里通过 call 的方式,让 Socket 对象拥有了 stream 对象的属性及方法。
在 steam.js 内,addChunk 这个方法触发了 data 事件。
系统层面调度如下


image.png
// stream.js 285 行
function addChunk(stream, state, chunk, addToFront) {
  if (state.flowing && state.length === 0 && !state.sync) {
    state.awaitDrain = 0;
    stream.emit('data', chunk);
  } else {
    // update the buffer info.
    state.length += state.objectMode ? 1 : chunk.length;
    if (addToFront)
      state.buffer.unshift(chunk);
    else
      state.buffer.push(chunk);

    if (state.needReadable)
      emitReadable(stream);
  }
  maybeReadMore(stream, state);
}

listening

当调用 listen 方法的时候,会触发 listening 事件

服务端

server.listen(8686);
server.on('listening', () => {
   console.log('listening');
});

net.Server 有如下属性和方法

  • method: address

监听 IP 套接字,则返回操作系统报告的服务器的绑定 address、地址 family 名称和 port

  • method: getConnections
  • property: maxConnections
  • ...

客户端连接 Socket

建立连接

const client = net.createConnection(options[, connectListener])

返回的是 Socket 对象

值得注意的是,创建连接的时候,会在本地随机分配端口。

const client = net.createConnection(8686, () => {
  console.log("client 1");
});
const client2 = net.createConnection(8686, () => {
  console.log("client 2");
});

> client2.localPort
53866 // 
> client.localPort
53725

因为服务端和客户端都是本地的,我们也可以通过 lsof -i :8686 查看连接的情况

➜  ~ lsof -i :8686
COMMAND   PID        USER   FD   TYPE            DEVICE SIZE/OFF NODE NAME
node    57010 chenxiaochi   25u  IPv6 0xa4e6a264cb60551      0t0  TCP *:distinct (LISTEN)
node    57010 chenxiaochi   26u  IPv6 0xa4e6a264cb5f891      0t0  TCP localhost:distinct->localhost:53725 (ESTABLISHED)
node    57010 chenxiaochi   27u  IPv6 0xa4e6a265642f231      0t0  TCP localhost:distinct->localhost:53866 (ESTABLISHED)
node    64411 chenxiaochi   27u  IPv4 0xa4e6a2653a2c8b9      0t0  TCP localhost:53725->localhost:distinct (ESTABLISHED)
node    64411 chenxiaochi   28u  IPv4 0xa4e6a26539ffd09      0t0  TCP localhost:53866->localhost:distinct (ESTABLISHED)

事件

  • connect
  • data
  • end
  • white
  • ...

data 事件

当服务端向客户端发送消息的时候,会触发此事件

客户端

➜ telnet localhost 8686
Trying ::1...
Connected to localhost.
Escape character is '^]'.
create connect

hello world
hello world // 服务端返回结果

属性

socket.localPort
socket.localAddress
...

总结

可以多写一些例子,加强理解。Net 模块是 Nodejs 比较重要的模块。看源码的过程中,也看到了对 stream 模块, async_hook 模块的依赖,更深一层还涉及到系统层面 libuv 的调度。这些更底层,能了解多一些,对 nodejs 服务的运行会有更清晰的认知。

文档阅读

https://nodejs.org/docs/latest-v10.x/api/net.html

相关文章

网友评论

      本文标题:Nodejs net 模块学习及源码阅读

      本文链接:https://www.haomeiwen.com/subject/wosywltx.html