node.js之net模块
net
net
模块是Node.js的核心模块之一,net
模块主要用于创建TCP服务器和TCP客户端,以及处理网络通信。
net模块主要包含两部分:
net.Server
类:通常用于创建一个 TCP 或本地服务器,内部通过socket来实现与客户端的通信。net.Socket
类:TCP或本地 socket的node版实现,net.Socket
实例实现了全双工的stream接口。net.Socket
可以由用户创建并直接用于与服务器交互,例如,它由net.createConnection()
返回,因此用户可以使用它与服务器对话。它也可以由 Node.js 创建并在收到连接时传递给用户,例如,它被传递给net.Server
上触发的 connection事件的监听器,因此用户可以使用它与客户端进行交互。
Socket 是对 TCP/IP 协议族的一种封装,是应用层与TCP/IP协议族通信的中间软件抽象层。它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。 Socket 还可以认为是一种网络间不同计算机上的进程通信的一种方法,利用三元组(ip地址,协议,端口)就可以唯一标识网络中的进程,网络中的进程通信可以利用这个标志与其它进程进行交互。
TCP
TCP是一种面向连接的、可靠的传输协议,用于在计算机网络上进行数据传输,是应用层和网络层之间的传输层协议。
TCP的特点:
- 可靠性:TCP通过使用确认机制、序列号和重传策略来确保数据的可靠传输。它可以检测并纠正数据丢失、重复、损坏或失序的问题。
- 面向连接:在进行数据传输之前,TCP需要在发送方和接收方之间建立一个连接。连接的建立是通过三次握手来完成的,确保双方都准备好进行通信。
- 全双工通信:TCP支持双方同时进行双向通信,即发送方和接收方可以在同一时间发送和接收数据。
- 流式传输:TCP一次传输的报文长度有限制,若太大则需要分块、分次传输。TCP将数据视为连续的字节流进行传输,而不是离散的数据包。
- 拥塞控制:TCP具备拥塞控制机制,用于避免网络拥塞和数据丢失。它通过动态调整发送速率、使用拥塞窗口和慢启动算法等方式来控制数据的发送速度。
net模块方法和属性
net.createServer([options][, connectionListener])
:两个参数都是可选的,创建一个 TCP 服务器。参数 connectionListener 是函数类型,是connection 事件监听器的回调函数。
net.createConnection(options[, connectionListener])
:创建一个到端口 port 和 主机 host的 TCP 连接。 host 默认为 'localhost'。第一个参数是配置对象,包含端口port和主机host的配置;第二个参数可选,connectListener 将会作为监听器添加到connect事件。返回 net.Socket
类。
net.isIP(input)
:检测输入的是否为 IP 地址。 IPV4 返回 4, IPV6 返回 6,其他情况返回 0。
net.isIPv4(input)
:如果输入的地址为 IPV4, 返回 true,否则返回 false。
net.isIPv6(input)
:如果输入的地址为 IPV6, 返回 true,否则返回 false。
net.Server类
net.createServer([options][, connectionListener])
创建了一个TCP 服务器,就是net.Server
类的实例sever对象。
方法和属性
server.listen()
:启动监听连接的服务器,可以监听 TCP 或 IPC 服务器,具体取决于它监听的内容。
server.listen([port[, host[, backlog]]][, callback])
用于 TCP 服务器的监听。监听指定端口port 和主机host。 默认情况下 host 接受任何 IPv4 地址的直接连接。端口 port 为 0 时,则会分配一个随机端口。server.listen(path[, backlog][, callback])
用于 IPC服务器的监听
server.listen()
函数是异步的。当服务器开始监听时,将触发listening
事件,最后一个参数callback
将被添加为listening
事件的监听器。
server.close([callback])
:关闭服务器,停止接收新的客户端请求,保持现有连接。注意事项如下:
- 对正在处理中的客户端请求,服务器会等待它们处理完(或超时),然后再正式关闭。
- 正常关闭的同时,callback 会被执行,同时会触发 close 事件。
- 异常关闭的同时,callback 也会执行,同时将对应的 error 作为参数传入。比如还没调用
server.listen()
之前,就调用了server.close()
。
已调用
server.listen()
正常关闭,close事件触发,然后callback执行,error参数为undefined。未调用server.listen()
异常关闭,close事件触发,然后callback执行,error为具体的错误信息。
server.close()
是异步函数,当所有连接结束的时候服务器会关闭,并会触发close
事件,参数callback
将被添加为close
事件的监听器。
server.address()
:返回服务端的地址信息,比如绑定的ip地址、端口、协议族名等
console.log( server.address() );
// 输出如下 { port: 3000, family: 'IPv4', address: '127.0.0.1' }
server.unref()
:如果这是事件系统中唯一一个活动的服务器,调用 unref 将允许程序退出。
server.ref()
:与 unref 相反,如果这是唯一的服务器,在之前调用了 unref的服务器上调用 ref 将不会让程序退出(默认行为)。如果服务器已经被 ref,则再次调用 ref 并不会产生影响。
ref主要用于将server 加入事件循环以及unref将server从事件循环里面剔除,影响就在于会不会影响进程的退出。
事件
- listening:调用
server.listen()
,正式开始监听请求的时候触发。 - connection:当有新的请求进来时触发,参数为请求相关的 socket。
- close:服务端关闭的时候触发。注意,如果存在连接,这个事件不会被触发直到所有的连接关闭。
- error:服务出错的时候触发,比如监听了已经被占用的端口。
net.Socket类
net.Socket
类的实例对象是 TCP 或 UNIX Socket 的抽象。net.Socket
实例实现了一个双工流接口。实例对象可以由用户创建,使用net.createConnection(options[, connectionListener])
或者由 Node 创建,并通过 connection 服务器事件传递给用户。
方法和属性
连接相关
socket.connect()
:在给定套接字上启动连接。
socket.connect(port[, host][, connectListener])
用于 TCP 连接。指定端口 port 和 主机 host,参数 host 默认为 localhost。socket.connect(path[, connectListener])
用于 IPC 连接,打开指定路径的 unix socket。
TCP用主机的IP地址加上主机上的端口号作为TCP连接的端点,这种端点就叫做套接字。套接字用IP地址:端口号表示
socket.setTimeout(timeout[, callback])
:用来进行连接超时设置。socket 闲置时间超过 timeout 毫秒后 ,将 socket 设置为超时。
socket.setKeepAlive([enable][, initialDelay])
:用来禁用或启用长连接功能,并在发送第一个在闲置 socket 上的长连接 probe 之前,可选地设定初始延时。默认为 false。 设定 initialDelay (毫秒),来设定收到的最后一个数据包和第一个长连接probe之间的延时。将 initialDelay 设为0,将会保留默认(或者之前)的值。默认值为0。
socket.destroy()
:当错误发生时,用来销毁socket。确保没有 I/O 活动在这个套接字上,只有在错误发生情况下才需要。(处理错误等等)。
数据读、写相关
socket.write(data[, encoding][, callback])
:在 socket 上发送数据。第二个参数指定了字符串的编码,默认是 UTF8 编码。
socket.end([data][, encoding])
:半关闭 socket。例如,它发送一个 FIN 包,可能服务器仍在发送数据。
socket.pause()
:暂停读取数据。就是说,不会再触发 data 事件。对于控制上传非常有用。
socket.resume()
:调用 pause() 后想恢复读取数据。
socket.setEncoding([encoding])
:设置编码
socket.setNoDelay([noDelay])
:禁用纳格(Nagle)算法。默认情况下 TCP 连接使用纳格算法,在发送前会缓冲数据。将 noDelay 设置为 true 将会在调用 socket.write()
时立即发送数据。noDelay 默认值为 true。
数据属性相关
socket.bufferSize
:该属性显示了要写入缓冲区的字节数。
socket.bytesRead
:接收到得字节数。
socket.bytesWritten
:发送的字节数。
事件循环相关
socket.unref()
:如果这是事件系统中唯一一个活动的服务器,调用 unref 将允许程序退出。如果服务器已被 unref,则再次调用 unref 并不会产生影响。
socket.ref()
:与 unref 相反,如果这是唯一的服务器,在之前被 unref 了的服务器上调用 ref 将不会让程序退出(默认行为)。如果服务器已经被 ref,则再次调用 ref 并不会产生影响。
地址相关
socket.address()
:操作系统返回绑定的地址,协议族名和服务器端口。返回的对象有 3 个属性,比如{ port: 12346, family: 'IPv4', address: '127.0.0.1' }
。
socket.remoteAddress
:远程的 IP 地址字符串,例如:'74.125.127.100' or '2001:4860:a005::68'
。
socket.remoteFamily
:远程IP协议族字符串,比如 IPv4或者IPv6。
socket.remotePort
:远程端口,数字表示,例如:80 or 21。
socket.localAddress
:网络连接绑定的本地接口 远程客户端正在连接的本地 IP 地址,字符串表示。例如,如果在监听'0.0.0.0'而客户端连接在'192.168.1.1',这个值就会是 '192.168.1.1'。
socket.localPort
:本地端口地址,数字表示。例如:80 or 21。
事件
- data:当收到另一侧传来的数据时触发。
- connect:当连接建立时触发。
- close:连接断开时触发。如果是因为传输错误导致的连接断开,则参数为error。
- end:当连接另一侧发送了 FIN 包的时候触发。默认情况下(allowHalfOpen == false),socket会完成自我销毁操作。但也可以把 allowHalfOpen 设置为 true,这样就可以继续往socket里写数据。当然,最后需要手动调用
socket.end()
- error:当有错误发生时,就会触发,参数为error。
- timeout:提示用户,socket 已经超时,需要手动关闭连接。
- drain:当写缓存空了的时候触发。(不是很好描述,具体可以看下stream的介绍)
- lookup:域名解析完成时触发。
TCP使用场景
服务端之间通信
服务端之间的通信可以直接使用TCP协议,而不需要上升到http协议。比如A服务器提供的接口B服务器可以不用通过调用接口的形式。
server.js:创建一个TCP服务,并且发送套接字,监听端口号3000
import net from 'net'
// 创建TCP服务
const sever = net.createServer(socket => {
// 函数参数中的socket参数可以用于接受和发送消息
// 发送消息
setInterval(() => {
socket.write('hello');
},6000);
// 接受消息
socket.on('data',(e) => {
console.log(e.toString());
})
});
// 监听端口
sever.listen(3000,() => {
console.log('3000 端口的服务正在监听');
});
client.js:连接server端,并且监听返回的数据
import net from 'net'
// 创建客户端,监听返回的数据
const client = net.createConnection({
// 配置对象包含需要监听服务器的主机和端口
port:3000,
host:'127.0.0.1'
});
// 监听data事件,接收到数据时触发
client.on('data',(e) => {
console.log(e.toString());
});
// 客户端发送消息
client.write('world');
在传输层实现应用层的http协议
创建一个TCP服务
import net from 'net'
// 给客户端返回的数据
const html = `<h1>暗号</h1><h2>tiamo</h2>`;
// 给客户端返回的HTTP响应报文
const response = [
'HTTP/1.1 200 OK', // 响应行:http版本号、状态码
'Content-Type: text/html;charset=utf-8', // 响应头:返回的数据类型
`Content-Length: ${html.length}`, // 响应头:返回数据的长度
'\r\n', // 换行,响应头后面换行接响应体
html // 响应体,返回的具体数据位于响应体
];
// 创建TCP服务
const http = net.createServer(socket => {
// 函数参数中的socket参数可以用于接受和发送消息
// 接受消息
socket.on('data',(e) => {
// 此时接受的消息就是HTTP请求报文,包含请求行、请求头、请求体
console.log(e.toString());
// 发送GET请求就返回数据
if(/GET/.test(e.toString())){
// 发送消息
socket.write(response.join('\r\n'));
// 消息发送完成后,断开链接,避免客户端还处于链接状态
socket.end();
}
})
});
// 监听端口
http.listen(8089,() => {
console.log('8089 端口的服务正在监听');
});
使用浏览器发送了一个http的get 请求,可以通过关键字get返回相关的内容例如html
net.createServer
创建 Unix
域套接字并且返回一个server对象接受一个回调函数,回调函数的参数是socket。
socket
可以监听很多事件
close
一旦套接字完全关闭就触发connect
当成功建立套接字连接时触发data
接收到数据时触发end
当套接字的另一端表示传输结束时触发,从而结束套接字的可读端
转载自:https://juejin.cn/post/7374239850077159476