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, which students who know socket programming should be familiar with:
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 an overview. 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: Receive a request from the client
Server: Receive client data with the content {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, then the callback is executed, the error parameter is undefined
server.listen() is not called: Abnormal shutdown, the close event is triggered, then the callback is executed, and 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()
Understand the node event loop Students should be familiar with these two APIs. 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, 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 triggers
2. connection triggers
Client net.Socket
At the beginning of the article I have already given an example of the client, so I will post another example here. (Remarks: Strictly speaking, net.Socket should not be called a client. It is just convenient to explain here.)
Just looking at the official node documentation, I feel that net.Socket is much more complicated than net.Server and has more APIs. events, properties. But in fact, if you classify the APIs, events, and properties related to net.Socket, you will find that it is not particularly complicated.
Please see the next section for details.
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 and attribute classification
The following APIs and attributes of net.Socket are roughly classified according to their uses to facilitate readers to better understand. Most of the APIs and properties are relatively simple. You will know what they do by reading the documentation, so I won’t expand on them here.
Connection related
socket.connect(): There are 3 different parameters, used in different scenarios;
socket.setTimeout(): used to set the connection timeout.
socket.setKeepAlive(): used to set a long connection.
socket.destroy(), socket.destroyed: used to destroy the socket when an error occurs to ensure that there will be no other IO operations on this socket.
Data reading and writing related
socket.write(), socket.end(), socket.pause(), socket.resume(), socket.setEncoding(), socket.setNoDelay()
Data attribute related
socket.bufferSize, socket.bytesRead, socket.bytesWritten
event loop related
socket.ref(), socket.unref()
address related
socket.address()
socket.remoteAddress, socket.remoteFamily, socket.remotePort
socket.localAddress/socket.localPort
Event introduction
data: Triggered when data from the other side is received.
connect: Triggered when the connection is established.
close: Triggered when the connection is disconnected. If the connection is disconnected due to a transmission error, the parameter is error.
end: Triggered when the other side of the connection sends a FIN packet (readers can review how HTTP disconnects). By default (allowHalfOpen == false), the socket will complete the self-destruction operation. But you can also set allowHalfOpen to true so that you can continue to write data to the socket. Of course, in the end you need to manually call socket.end()
error: it will be triggered when an error occurs, and the parameter is error. (The official document basically mentions it in one sentence, but considering that there may be too many errors, it is understandable)
timeout: Prompts the user that the socket has timed out and the connection needs to be closed manually.
drain: Triggered when the write cache is empty. (It’s not very easy to describe, please see the introduction below for details)
lookup: Triggered when domain name resolution is completed.