Node.js之TCP(net)

Hi I'm Shendi


Node.js之TCP(net)


最近使用Nodejs编写程序,需要用到自己编写的分布式工具,于是需要将Java版的用NodeJs重新写一遍,需要使用到TCP通信,于是在这里记录下Node.js TCP 的使用方法

依赖

需要使用到 net 模块,是 node.js 的核心模块,直接可以引入使用

js 复制代码
const net = require('net');

TCP服务端

Node.js 将服务端和客户端区分开了,使用起来还是非常的简单,服务端大概就是监听连接,读写数据

创建TCP服务端

通过 createServer 函数来创建一个服务端,函数接收一个回调函数,用于处理新的客户端连接,回调函数有一个参数 socket,代表与客户端的连接,通过socket来读取客户端发送的数据,以及发送数据给客户端

函数返回 net.Server

示例如下

js 复制代码
var server = net.createServer(function (socket) {
    console.log("有新的客户端连接了");
});

监听端口

创建了服务端后,还需要指定监听的端口,相当于启动服务端

通过 listen 函数

js 复制代码
var port = 80;
server.listen(port, function () {
    // 在启动成功后执行
    console.log(`服务端已启动,端口:${that.port}`);
});

获取客户端ip

在创建TCP服务端部分,传递了一个回调函数,回调函数有一参数 socket,通过这个参数来处理关于客户端的操作,包括获取ip

通过 remoteAddress 获取到 ip,但是获取到的ip是 ipv6格式的,其中包含了ipv4地址

IP地址以::ffff:开头表示该IP地址是一个IPv4地址嵌入在IPv6地址中的表示方式。IPv6地址是128位长,而IPv4地址只有32位长,为了在IPv6环境中使用IPv4地址,可以使用该表示方式。

于是要拿到具体ip需要进行额外的操作,这里我就使用最简单的,字符串截取

js 复制代码
let ip = socket.remoteAddress;
ip = ip.substring(ip.lastIndexOf(":") + 1);

这样就拿到正确的ip了

设置超时时间

使用 socket.setTimeout 来设置超时时间,函数接收两个参数,一个超时时间(秒),一个回调函数。

当socket在指定的时间内没有收到任何新的数据时,将会触发回调。

例如五秒没有收到数据就关闭连接

js 复制代码
socket.setTimeout(5000, () => {
    socket.end();
});

读取数据

通过 on 监听 data 事件来读取数据

js 复制代码
// data 为 Buffer 类型
socket.on("data", function (data) {
    console.log(data.toString());
});

因为是 TCP,有可能粘包、拆包之类的,所以一般都有对应的自定义协议,以及缓冲区

例如一个完整的协议数据以字节 20 结尾,示例代码如下

js 复制代码
// 读取的数据缓存
var readData = Buffer.from([]);

// 收到数据触发data事件
socket.on("data", function (data) {
    readData = Buffer.concat([readData, data]);
    let index = readData.indexOf(Buffer.from([20]));
    if (index != -1) {
        // 读取到了一个完整的协议数据,进行处理
        let pData = readData.subarray(0, index + 1);
        // 处理...
        console.log(pData.toString());
        // 处理完从缓存中移除这部分数据
        readData = readData.subarray(index + 1, readData.length);
    } else {
        // 没有读取到完整的协议数据,不做操作
    }
});

发送数据

通过 write 来发送数据,其中第一个参数为要发送的数据,可以为字符串和Uint8Array(Buffer是其子类)

第二个参数为发送成功的回调

js 复制代码
socket.write("hello,world", function () {
    console.log(`发送成功,数据长度为:${socket.bytesWritten}`);
});

事件处理

不管是服务端还是socket,都可以通过 on 来监听事件,同读取数据那样

服务端Server的事件

名称 描述
listening 调用 server.listen 后触发
connection 当新连接创建后会被触发。socket 是 net.Socket实例
close 服务器关闭时会触发。注意,如果存在连接,这个事件不会被触发直到所有的连接关闭
error 发生错误时触发

Socket的事件

名称 描述
lookup 在解析域名后,但在连接前,触发这个事件。对 UNIX sokcet 不适用
connect 成功建立 socket 连接时触发
data 当接收到数据时触发
end 当 socket 另一端发送 FIN 包时,触发该事件
timeout 当 socket 空闲超时时触发,仅是表明 socket 已经空闲。用户必须手动关闭连接
drain 当写缓存为空时触发。可用来控制上传
error 错误发生时触发
close 当 socket 完全关闭时触发。参数 had_error 是布尔值,它表示是否因为传输错误导致 socket 关闭

报错处理 Error: read ECONNRESET,导致服务端程序挂掉

错误图如下

这个问题出现是客户端没有调用 close 关闭连接,但客户端挂了(例如任务管理器强行停止),但这种情况是很常见的,对于服务端来说,不可能因为这种小问题而导致整个服务端程序挂掉

解决办法就是给socket增加error事件

js 复制代码
socket.on('error', function(err) {
    console.log(`客户端出错,err:${err}`);
    that.connNum--;
});

这样出错会被捕获,不会导致整个程序挂掉了

TCP客户端

客户端的使用方式大体和服务端差不多

创建 TCP 客户端

通过 net 模块的 createConnection 创建客户端,函数返回 net.Socket,与上面服务端的Socket是一样的类型,所以使用方法也是一样的

函数有两个参数,第一个端口号,第二个主机名,域名/地址

js 复制代码
let socket = net.createConnection(port, host);

具体使用

与服务端部分的socket使用是一样的,所以这里就直接贴出示例代码了

js 复制代码
let socket = net.createConnection(80, "127.0.0.1");

// 发送数据
socket.write(Buffer.from("Shendi"));
socket.on('data', (data) => {
    console.log(`接收到数据: ${data}`);
});

conn.client.on('end', function(data) {
   	console.log(`客户端连连接关闭`);
});

conn.client.on('error', function(err) {
    console.log(`客户端连接出错,err:${err}`);
});

END

相关推荐
一天八小时28 分钟前
计算机网络————(一)HTTP讲解
网络协议·计算机网络·http
yourkin66611 小时前
TCP...
服务器·网络·tcp/ip
哑巴语天雨12 小时前
前端面试-网络协议篇
websocket·网络协议·http·面试·https
垣宇13 小时前
Vite 和 Webpack 的区别和选择
前端·webpack·node.js
ktkiko1114 小时前
Websocket——心跳检测
网络·websocket·网络协议
爱吃南瓜的北瓜14 小时前
npm install 卡在“sill idealTree buildDeps“
前端·npm·node.js
翻滚吧键盘14 小时前
npm使用了代理,但是代理软件已经关闭导致创建失败
前端·npm·node.js
浪九天15 小时前
node.js的版本管理
node.js
小梁不秃捏15 小时前
HTTP 常见状态码技术解析(应用层)
网络·网络协议·计算机网络·http
浪九天16 小时前
node.js的常用指令
node.js