TCP 服务在网络应用中十分常见,目前大多数的应用都是基于TCP搭建而成的。
TCP 全名为传输控制协议,在 OSI 模型(由七层模型,分别为物理层、数据链路层、网络层、传输层、会话层、表示层、应用层)中属于传输层协议。许多应用层协议基于TCP构建,典型的是HTTP、SMTP、IMAP等协议。
七层协议示意图如下:
层级 | 作用 |
---|---|
应用层 | HTTP、SMTP、IMAP等 |
表示层 | 加密/解密等 |
会话层 | 通信连接/维持会话 |
传输层 | TCP/UDP |
网络层 | IP |
链路层 | 网络特有的链路接口 |
物理层 | 网络物理硬件 |
TCP 是面向连接的协议,其显著的特征是在传输之前需要3次握手形成会话,如下图所示
只有会话形成之后,服务器端和客户端之间才能互相发送数据。在创建会话的过程中,服务器端和客户端分别提供一个套接字,这个两个套接字共同形成一个连接。服务器端与客户端则通过套接字实现两者之间连接通信的操作。下面是一个基于 Socket 套接字编程的网络通信模型。
基本示例
服务端:
const net = require('net');
const server = net.createServer((c) => {
// 'connection' listener
console.log('client connected');
c.on('end', () => {
console.log('client disconnected');
});
c.write('hello\r\n');
c.pipe(c);
});
server.on('error', (err) => {
throw err;
});
server.listen(8124, () => {
console.log('server bound');
});
客户端:
const net = require('net');
const client = net.createConnection({ port: 8124 }, () => {
// 'connect' listener
console.log('connected to server!');
client.write('world!\r\n');
});
client.on('data', (data) => {
console.log(data.toString());
client.end();
});
client.on('end', () => {
console.log('disconnected from server');
});
相关 API
官方API文档:https://nodejs.org/dist/latest-v10.x/docs/api/net.html
服务端相关 API
- [new net.Server(options][, connectionListener]) 创建服务器
- Event: ‘close’ 当服务器关闭时,触发该事件
- Event: ‘connection’ 当有新的客户端连接进来时,触发该事件
- Event: ‘error’ 当服务器发生错误时,触发该事件
- Event: ‘listening’ 当调用 server.listen() 绑定端口后触发,简洁写法为 server.listen(port, listeningListener),通过 listen() 方法的第二个参数传入
- server.address() 服务器创建侦听成功后,可以用来获取服务器地址相关信息,包含
{ port: 12346, family: 'IPv4', address: '127.0.0.1' }
信息 - server.close([callback]) 当服务器关闭时触发,在调用 server.close() 后,服务器将停止接受新的套接字连接,但保持当前存在的连接,等待所有连接都断开后,会触发该事件
- server.connections 获取当前已建立连接的数量
- 注意:该 API 即将废弃,推荐使用
server.getConnections()
替换
- 注意:该 API 即将废弃,推荐使用
- server.getConnections(callback) 获取当前已建立连接的数量
- server.listen() 绑定端口号启动服务,开始等待侦听
- [server.listen(handle, backlog][, callback])
- [server.listen(options, callback])
- [server.listen(path, backlog][, callback])
- [server.listen(port[, host[, backlog]]][, callback])
- server.listening 获取服务器的侦听状态
- server.maxConnections 在服务器连接数较高的时候,可以通过设置该属性用于拒绝超过最大数的连接
- server.ref() 恢复服务器侦听
- server.unref() 暂停服务器侦听,可以使用
server.ref()
恢复服务器侦听
套接字 Socket 相关 API
- new net.Socket([options]) 创建 Socket 连接
- Event: ‘close’ 当套接字完全关闭时,触发该事件
- Event: ‘connect’ 该事件用于客户端,当套接字与服务端连接成功时会被触发
- Event: ‘data’ 当一端调用
write()
发送数据时,另一端会触发data
事件,事件传递的数据即是write()
发送的数据 - Event: ‘drain’ 当任意一端调用 write() 发送数据时,当前这端会触发该事件
- Event: ‘end’ 当连接中的任意一端发送了 FIN 数据时,将会触发该事件
- Event: ‘error’ 当异常发生时,触发该事件
- Event: ‘timeout’ 当一定时间后连接不再活跃时,该事件将会被触发,通知用户当前连接已经被闲置了
- socket.address() 获取套接字的连接信息,例如
{ port: 12346, family: 'IPv4', address: '127.0.0.1' }
- socket.localAddress 获取当前套接字地址
- socket.localPort 获取当前套接字端口号
- socket.remoteAddress 获取另一端套接字地址
- socket.remoteFamily 获取另一端套接字IP协议版本
- socket.remotePort 获取另一端套接字连接端口号
- socket.setEncoding([encoding]) 设置获取数据解析的编码格式,默认不处理
- socket.write(data[, encoding][, callback]) 通过套接字发送数据
其它 API
- net.connect() 创建 Socket 客户端连接,和
net.createConnection()
作用相等- net.connect(options[, connectListener])
- [net.connect(port, host][, connectListener])
- net.createConnection() 创建 Socket 客户端连接
- [net.createServer(options][, connectionListener]) 创建Socket服务端,等价于
new net.Server()
- net.isIP(input) 判断是否是IP地址
- net.isIPv4(input) 判断是否是符合 IPv4协议的地址
- net.isIPv6(input) 判断是否是符合 IPv6 协议的地址