Module Overview
net module is also the core module of nodejs. As mentioned in the http module overview, http.Server inherits net.Server. In addition, the communication between the http client and the http server relies on socket (net.Socket). In other words, when doing node server programming, net is basically a module that cannot be avoided.
From the composition point of view, the net module mainly consists of two parts. Students who know socket programming should be familiar with it:
net.Server: TCP server, which communicates with the client internally through sockets.
net.Socket: The node version implementation of tcp/local socket, which implements the full-duplex stream interface.
This article starts with a simple tcp server/client example to give readers a general understanding. Then we will introduce the more important APIs, properties, and events of net.Server and net.Socket respectively.
For beginners, it is recommended to run the examples in the article locally to deepen their understanding.
Simple server+client example
tcp server program is as follows:
var net = require('net'); var PORT = 3000; var HOST = '127.0.0.1'; // tcp服务端 var server = net.createServer(function(socket){ console.log('服务端:收到来自客户端的请求'); socket.on('data', function(data){ console.log('服务端:收到客户端数据,内容为{'+ data +'}'); // 给客户端返回数据 socket.write('你好,我是服务端'); }); socket.on('close', function(){ console.log('服务端:客户端连接断开'); }); }); server.listen(PORT, HOST, function(){ console.log('服务端:开始监听来自客户端的请求'); });
tcp client is as follows:
var net = require('net'); var PORT = 3000; var HOST = '127.0.0.1'; // tcp客户端 var client = net.createConnection(PORT, HOST); client.on('connect', function(){ console.log('客户端:已经与服务端建立连接'); }); client.on('data', function(data){ console.log('客户端:收到服务端数据,内容为{'+ data +'}'); }); client.on('close', function(data){ console.log('客户端:连接断开'); }); client.end('你好,我是客户端');
Run the server and client code, and the console output is as follows:
Server:
Server : Start listening for requests from the client
Server: Received a request from the client
Server: Received client data, the content is {Hello, I am the client}
Server: The client connection is disconnected
Client:
Client: A connection has been established with the server
Client: Received server data, the content is {Hello, I am the server}
Client: The connection is disconnected
Server net.Server
server.address()
Returns the address information of the server, such as the bound IP address, port, etc.
console.log( server.address() ); // 输出如下 { port: 3000, family: 'IPv4', address: '127.0.0.1' }
server.close(callback])
Close the server and stop receiving new client requests. There are a few things to note:
For client requests that are being processed, the server will wait for them to be processed (or timeout) before officially shutting down.
During normal shutdown, the callback will be executed and the close event will be triggered.
When the exception is closed, the callback will also be executed, and the corresponding error will be passed in as a parameter. (For example, server.close() is called before server.listen(port) is called)
The following will be compared through two specific examples, and the conclusions are listed first
server.listen() has been called: Normal shutdown, the close event is triggered, and then the callback is executed. The error parameter is undefined. Server.listen() is not called: Abnormal shutdown, the close event is triggered, and then the callback is executed. The error is the specific error message. (Note that the error event is not triggered)
Example 1: The server is shut down normally
var net = require('net'); var PORT = 3000; var HOST = '127.0.0.1'; var noop = function(){}; // tcp服务端 var server = net.createServer(noop); server.listen(PORT, HOST, function(){ server.close(function(error){ if(error){ console.log( 'close回调:服务端异常:' + error.message ); }else{ console.log( 'close回调:服务端正常关闭' ); } }); }); server.on('close', function(){ console.log( 'close事件:服务端关闭' ); }); server.on('error', function(error){ console.log( 'error事件:服务端异常:' + error.message ); });
The output is:
close event: The server is shut down
close callback: The server is shut down normally
Example 2: The server is shut down abnormally
The code is as follows
var net = require('net'); var PORT = 3000; var HOST = '127.0.0.1'; var noop = function(){}; // tcp服务端 var server = net.createServer(noop); // 没有正式启动请求监听 // server.listen(PORT, HOST); server.on('close', function(){ console.log( 'close事件:服务端关闭' ); }); server.on('error', function(error){ console.log( 'error事件:服务端异常:' + error.message ); }); server.close(function(error){ if(error){ console.log( 'close回调:服务端异常:' + error.message ); }else{ console.log( 'close回调:服务端正常关闭' ); } });
The output is:
close event: Server is closed
close callback: Server exception: Not running
server.ref()/server.unref()
Students who understand the node event loop These two APIs should be familiar to you. They are mainly used to add/remove the server from the event loop. The impact lies in whether it will affect the exit of the process.
For students who are studying net, there is no need to pay special attention. If you are interested, just do the experiment by yourself.
Event listening/connection/close/error
listening: Call server.listen(), triggered when the listening request is officially started.
connection: Triggered when a new request comes in, and the parameter is the socket related to the request.
close: Triggered when the server is closed.
error: Triggered when a service error occurs, such as monitoring a port that is already occupied.
Several events are relatively simple. Here is just an example of connection.
It can be seen from the test results that when a new client connection is generated, the callback in net.createServer(callback) will be called, and the callback function registered for the connection event will also be called.
In fact, the callback in net.createServer(callback) is also added as a listening function for the connection event in the internal implementation of node. If you are interested, you can take a look at the source code of node.
var net = require('net'); var PORT = 3000; var HOST = '127.0.0.1'; var noop = function(){}; // tcp服务端 var server = net.createServer(function(socket){ socket.write('1. connection 触发\n'); }); server.on('connection', function(socket){ socket.end('2. connection 触发\n'); }); server.listen(PORT, HOST);
Test the effect through the following command
curl http://127.0.0.1:3000
Output:
1. connection trigger 2. connection trigger
client net.Socket
在文章开头已经举过客户端的例子,这里再把例子贴一下。(备注:严格来说不应该把 net.Socket 叫做客户端,这里方便讲解而已)
单从node官方文档来看的话,感觉 net.Socket 比 net.Server 要复杂很多,有更多的API、事件、属性。但实际上,把 net.Socket 相关的API、事件、属性 进行归类下,会发现,其实也不是特别复杂。
具体请看下一小节内容。
var net = require('net'); var PORT = 3000; var HOST = '127.0.0.1'; // tcp客户端 var client = net.createConnection(PORT, HOST); client.on('connect', function(){ console.log('客户端:已经与服务端建立连接'); }); client.on('data', function(data){ console.log('客户端:收到服务端数据,内容为{'+ data +'}'); }); client.on('close', function(data){ console.log('客户端:连接断开'); }); client.end('你好,我是客户端');
API、属性归类
以下对net.Socket的API跟属性,按照用途进行了大致的分类,方便读者更好的理解。大部分API跟属性都比较简单,看下文档就知道做什么的,这里就先不展开。
连接相关
socket.connect():有3种不同的参数,用于不同的场景;
socket.setTimeout():用来进行连接超时设置。
socket.setKeepAlive():用来设置长连接。
socket.destroy()、socket.destroyed:当错误发生时,用来销毁socket,确保这个socket上不会再有其他的IO操作。
数据读、写相关
socket.write()、socket.end()、socket.pause()、socket.resume()、socket.setEncoding()、socket.setNoDelay()
数据属性相关
socket.bufferSize、socket.bytesRead、socket.bytesWritten
事件循环相关
socket.ref()、socket.unref()
地址相关
socket.address()
socket.remoteAddress、socket.remoteFamily、socket.remotePort
socket.localAddress/socket.localPort
事件简介
data:当收到另一侧传来的数据时触发。
connect:当连接建立时触发。
close:连接断开时触发。如果是因为传输错误导致的连接断开,则参数为error。
end:当连接另一侧发送了 FIN 包的时候触发(读者可以回顾下HTTP如何断开连接的)。默认情况下(allowHalfOpen == false),socket会完成自我销毁操作。但你也可以把 allowHalfOpen 设置为 true,这样就可以继续往socket里写数据。当然,最后你需要手动调用 socket.end()
error:当有错误发生时,就会触发,参数为error。(官方文档基本一句话带过,不过考虑到出错的可能太多,也可以理解)
timeout:提示用户,socket 已经超时,需要手动关闭连接。
drain:当写缓存空了的时候触发。(不是很好描述,具体可以看下stream的介绍)
lookup:域名解析完成时触发。