Node.js net模块的使用示例

2025-02-28 05:50
文章标签 模块 使用 js 示例 net node

本文主要是介绍Node.js net模块的使用示例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Node.jsnet模块的使用示例》本文主要介绍了Node.jsnet模块的使用示例,net模块支持TCP通信,处理TCP连接和数据传输,具有一定的参考价值,感兴趣的可以了解一下...

简介

Node.js 的 net 模块提供了用于实现 TCP 服务器和客户端的异步网络 API。它是 Node.js 网络功能的核心,为上层模块如 HTTP、HTTPS 等提供了基础支持。本教程将全面介绍 net 模块的使用方法和最佳实践。

引入 net 模块

const net = require('net');

核心概念

TCP (传输控制协议)

TCP 是一种面向连接的、可靠的、基于字节流的传输层通信协议。net 模块主要处理 TCP 通信。

Socket

Socket 是网络通信的端点,在 Node.js 中表示为 net.Socket 类的实例。它可以是服务器与客户端之间建立的连接,也可以是客户端主动创建的连接。

服务器

服务器使用 net.Server 类创建,负责监听连接并处理客户端请求。

TCP 服务器创建

基本服务器

const net = require('net');

// 创建服务器
const server = net.createServer((socket) => {
  console.log('客户端已连接');
  
  // 接收数据
  socket.on('data', (data) => {
    console.log(`接收到数据: ${data}`);
    // 发送响应
    socket.write('服务器已收到你的消息');
  });
  
  // 连接关闭
  socket.on('end', () => {
    console.log('客户端已断开连接');
  });
  
  // 处理错误
  socket.on('error', (err) => {
    console.error('连接错误:', err);
  });
});

// 监听端口
server.listen(3000, () => {
  console.log('服务器启动成功,监听端口 3000');
});

服务器配置选项

创建服务器时可以传递配置选项:

const server = net.createServer({
  allowHalfOpen: false, // 当另一端发送 FIN 包时自动发送 FIN (默android认)
  pauseonConnect: false // 是否在连接时暂停套接字 (默认)
});

服务器事件

net.Server 类继承自 EventEmitter,支持以下主要事件:

  • listening: 服务器开始监听连接时触发
  • connection: 新客户端连接建立时触发
  • error: 发生错误时触发
  • close: 服务器关闭时触发
server.on('listening', () => {
  console.log('服务器开始监听连接');
});

server.on('connection', (socket) => {
  console.log('新客户端连接');
});

server.on('error', (err) => {
  console.error('服务器错误:', err);
});

server.on('close', () => {
  console.log('服务器已关闭');
});

TCP 客户端创建

基本客户端

const net = require('net');

// 创建连接
const client = net.createConnection({ 
  host: 'localhost',
  port: 3000 
}, () => {
  console.log('已连接到服务器');
  // 发送数据
  client.write('你好,服务器')www.chinasem.cn;
});

// 接收数据
client.on('data', (data) => {
  console.log(`接收到服务器响应: ${data}`);
  // 关闭连接
  client.end();
});

// 连接结束
client.on('end', () => {
  console.log('已断开与服务器的连接');
});

// 错误处理
client.on('error', (err) => {
  console.error('连接错误:', err);
});

客户端配置选项

创建客户端连接时可以传递多种配置选项:

const client = net.createConnection({
  host: 'localhost', // 主机名
  port: 3000,        // 端口号
  localAddress: '192.168.1.100', // 本地接口
  family: 4,         // IP 版本 (4 或 6)
  timeout: 5000      // 连接超时(毫秒)
});

Socket 对象

net.Socket 是 TCP 连接的抽象,具有流(Duplex Stream)的特性,既可读又可写。

创建 Socket

除了服务器自动创建外,也可以手动创建:

const socket = new net.Socket();
socket.connect(3000, 'localhost', () => {
  console.log('连接成功');
});

Socket 属性

  • socket.remoteAddress: 远程 IP 地址
  • socket.remotePort: 远程端口
  • socket.localAddress: 本地 IP 地址
  • socket.localPort: 本地端口
  • socket.bytesRead: 接收的字节数
  • socket.bytesWritten: 发送的字节数
socket.on('connect', () => {
  console.log(`连接到 ${socket.remoteAddress}:${socket.remotePort}`);
  console.log(`本地端口: ${socket.localPort}`);
});

Socket 方法

  • socket.write(data[, encoding][, callback]): 发送数据
  • socket.end([data][, encoding][, callback]): 结束连接
  • socket.destroy([error]): 强制关闭连接
  • socket.pause(): 暂停数据读取
  • socket.resume(): 恢复数据读取
  • socket.setKeepAlive([enable][, initialDelay]): 设置 keepalive
  • socket.setNoDelay([noDelay]): 禁用 Nagle 算法

事件处理

服务器事件

server.on('listening', () => {
  const address = server.address();
  console.log(`服务器监听 ${address.address}:${address.port}`);
});

server.on('error', (err) => {
  if (err.code === 'EADDRINUSE') {
    console.erroChina编程r('端口已被占用');
  }
});

Socket 事件

  • connect: 成功建立连接时触发
  • data: 接收到数据时触发
  • end: 对方结束发送数据时触发
  • timeout: 连接超时时触发
  • error: 发生错误时触发
  • close: 连接完全关闭时触发
socket.on('data', (data) => {
  console.log(`接收到数据: ${data.toString()}`);
});

socket.on('timeout', () => {
  console.log('连接超时');
  socket.end();
});

socket.on('close', (hadError) => {
  console.log(`连接关闭${hadError ? ',发生错误' : ''}`);
});

数据传输

发送数据

// 发送字符串
socket.write('Hello', 'utf8');

// 发送 Buffer
const buffer = Buffer.from([0x68, 0x65, 0x6c, 0x6c, 0x6f]);
socket.write(buffer);

// 使用回调确认数据已被发送
socket.write('World', () => {
  console.log('数据已发送');
});

接收数据

let chunks = [];

socket.on('data', (chunk) => {
  chunks.push(chunk);
});

socket.on('end', () => {
  const data = Buffer.concat(chunks).toString();
  console.log(`完整数据: ${data}`);
});

处理二进制数据

socket.on('data', (chunk) => {
  // 假设前两个字节表示消息长度
  const messageLength = chunk.readUInt16BE(0);
  const message = chunk.slice(2, 2 + messageLength);
  console.log(`消息内容: ${message.toString()}`);
});

高级特性

IPC (进程间通信)

除了 TCP 通信,net 模块也支持通过 Unix 域套接字或命名管道进行进程间通信:

// 服务器
const server = net.createServer().listen('/tmp/echo.sock');

// 客户端
const client = net.createConnection({ path: '/tmp/echo.sock' });

多连接管理

实际应用中,服务器通常需要管理多个连接:

const connections = new Map();

server.on('connection', (socket) => {
  const id = `${socket.remoteAddress}:${socket.remotePort}`;
  connections.set(id, socket);
  
  socket.on('close', () => {
    connections.delete(id);
    console.log(`客户端 ${id} 已断开,当前连接数: ${connections.size}`);
  });
});

// 向所有客户端广播消息
function broadcast(message) {
  for (const socket of connections.values()) {
    socket.write(message);
  }
}

重连机制

客户端断线重连php示例:

function createClient() {
  const client = net.createConnection({ port: 3000 });
  
  client.on('error', (err) => {
    console.error('连接错误:', err);
  });
  
  client.on('close', () => {
    console.log('连接关闭,尝试重连...');
    setTimeout(() => {
      createClient();
    }, 3000); // 3秒后重连
  });
  
  return client;
}

const client = createClient();

实际应用案例

简单聊天服务器

const net = require('net');
const clients = [];

const server = net.createServer((socket) => {
  // 为新连接分配昵称
  socket.name = `用户${clients.length + 1}`;
  
  // 广播新用户连接消息
  const message = `${socket.name} 已加入聊天室`;
  broadcast(message, socket);
  
  // 添加到客户端列表
  clients.push(socket);
  
  // 欢迎消息
  socket.write(`欢迎来到聊天室,${socket.name}!\n`);
  
  // 接收消息
  socket.on('data', (data) => {
    broadcast(`${socket.name}: ${data}`, socket);
  });
  
  // 断开连接
  socket.on('end', () => {
    clients.splice(clients.indexOf(socket), 1);
    broadcast(`${socket.name} 已离开聊天室`, socket);
  });
  
  // 处理错误
  socket.on('error', (err) => {
    console.error(`${socket.name} 发生错误:`, err);
  });
});

// 广播消息给所有客户端
function broadcast(message, sender) {
  clients.forEach((client) => {
    // 不发送给消息发送者
    if (client !== sender) {
      client.write(message);
    }
  });
  console.log(message);
}

server.listen(3000, () => {
  console.log('聊天服务器已启动,监听端口 3000');
});

简单的 HTTP 服务器

使用 net 模块实现基础 HTTP 服务器:

const net = require('net');

const server = net.createServer((socket) => {
  socket.on('data', (data) => {
    const request = data.toString();
    console.log('收到请求:', request);
    
    // 简单的 HTTP 响应
    const response = [
      'HTTP/1.1 200 OK',
      'Content-Type: text/html',
      'Connection: close',
      '',
      '<html><body><h1>Hello from Node.js net module</h1></body></html>'
    ].join('\r\n');
    
    socket.write(response);
    socket.end();
  });
  
  socket.on('error', (err) => {
    console.error('Socket 错误:', err);
  });
});

server.listen(8080, () => {
  console.log('HTTP 服务器运行在 http://localhost:8080/');
});

性能优化

使用 Buffer 池

对于高性能应用,可以使用 Buffer 池避免频繁创建新 Buffer:

const bufferPool = Buffer.allocUnsafe(1024 * 100); // 100KB 池
let offset = 0;

function allocateBuffer(size) {
  if (offset + size > bufferPool.length) {
    offset = 0; // 重置偏移
  }
  
  const buffer = bufferPool.slice(offset, offset + size);
  offset += size;
  return buffer;
}

// 使用预分配的 buffer 发送数据
const dataToSend = "Hello";
const buffer = allocateBuffer(dataToSend.length);
buffer.write(dataToSend);
socket.write(buffer);

避免小包发送

合并小数据包可以提高网络效率:

const queue = [];
let isFlushing = false;

function queueData(socket, data) {
  queue.push(data);
  
  if (!isFlushing) {
    isFlushing = true;
    process.nextTick(flushQueue, socket);
  }
}

function flushQueue(socket) {
  if (queue.length > 0) {
    const data = Buffer.concat(queue);
    queue.length = 0;
    socket.write(data);
  }
  isFlushing = false;
}

调整 Socket 参数

针对不同场景优化 Socket 设置:

// 低延迟应用 (禁用 Nagle 算法)
socket.setNoDelay(true);

// 长连接应用
socket.setKeepAlive(true, 60000); // 60秒

// 设置超时
socket.setTimeout(30000); // 30秒
socket.on('timeout', () => {
  console.log('连接超时');
  socket.end();
});

常见问题解答

Q: 如何处理 EADDRINUSE 错误?

A: 这个错误表示端口已被占用,可以通过以下方式处理:

server.on('error', (err) => {
  if (err.code === 'EADDRINUSE') {
    console.log('端口已被占用,尝试其他端口...');
    server.close();
    server.listen(port + 1);
  }
});

Q: 如何实现心跳机制?

A: 通过定时发送心跳包确保连接活跃:

// 服务端心跳检测
const clients = new Map();

server.on('connection', (socket) => {
  const id = `${socket.remoteAddress}:${socket.remotePort}`;
  clients.set(id, { socket, lastHeartbeat: Date.now() });
  
  socket.on('data', (data) => {
    if (data.toString() === 'PING') {
      clients.get(id).lastHeartbeat = Date.now();
      socket.write('PONG');
    }
  });
});

// 每10秒检查一次客户端心跳
setInterval(() => {
  const now = Date.now();
  for (const [id, client] of clients.entries()) {
    // 如果客户端30秒没有心跳,断开连接
    if (now - client.lastHeartbeat > 30000) {
      console.log(`客户端 ${id} 心跳超时,断开连接`);
      client.socket.destroy();
      clients.delete(id);
    }
  }
}, 10000);

// 客户端心跳
const client = net.createConnection({ port: 3000 });
setInterval(() => {
  client.write('PING');
}, 10000);

Q: 如何处理大量数据传输?

A: 使用流控制和数据分块:

const fs = require('fs');

// 发送大文件
function sendLargeFile(socket, filePath) {
  const fileStream = fs.createReadStream(filePath);
  
  fileStream.on('data', (chunk) => {
    // 检查缓冲区是否已满
    const canContinue = socket.write(chunk);
    
    if (!canContinue) {
      // 如果缓冲区已满,暂停读取
      fileStream.pause();
      
      // 当缓冲区清空后,恢复读取
      socket.once('drain', () => {
        fileStream.resume();
      });
    }
  });
  
  fileStream.on('end', () => {
    console.log('文件发送完成');
  });
}

到此这篇关于Node.js net模块的使用示例的文章就介绍到这了,更多相关Node.js net模块内容请搜索编程China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持China编程(www.chinasem.cn)! 

这篇关于Node.js net模块的使用示例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1153574

相关文章

Python并行处理实战之如何使用ProcessPoolExecutor加速计算

《Python并行处理实战之如何使用ProcessPoolExecutor加速计算》Python提供了多种并行处理的方式,其中concurrent.futures模块的ProcessPoolExecu... 目录简介完整代码示例代码解释1. 导入必要的模块2. 定义处理函数3. 主函数4. 生成数字列表5.

Python中help()和dir()函数的使用

《Python中help()和dir()函数的使用》我们经常需要查看某个对象(如模块、类、函数等)的属性和方法,Python提供了两个内置函数help()和dir(),它们可以帮助我们快速了解代... 目录1. 引言2. help() 函数2.1 作用2.2 使用方法2.3 示例(1) 查看内置函数的帮助(

Linux脚本(shell)的使用方式

《Linux脚本(shell)的使用方式》:本文主要介绍Linux脚本(shell)的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述语法详解数学运算表达式Shell变量变量分类环境变量Shell内部变量自定义变量:定义、赋值自定义变量:引用、修改、删

Java使用HttpClient实现图片下载与本地保存功能

《Java使用HttpClient实现图片下载与本地保存功能》在当今数字化时代,网络资源的获取与处理已成为软件开发中的常见需求,其中,图片作为网络上最常见的资源之一,其下载与保存功能在许多应用场景中都... 目录引言一、Apache HttpClient简介二、技术栈与环境准备三、实现图片下载与保存功能1.

Python中使用uv创建环境及原理举例详解

《Python中使用uv创建环境及原理举例详解》uv是Astral团队开发的高性能Python工具,整合包管理、虚拟环境、Python版本控制等功能,:本文主要介绍Python中使用uv创建环境及... 目录一、uv工具简介核心特点:二、安装uv1. 通过pip安装2. 通过脚本安装验证安装:配置镜像源(可

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

LiteFlow轻量级工作流引擎使用示例详解

《LiteFlow轻量级工作流引擎使用示例详解》:本文主要介绍LiteFlow是一个灵活、简洁且轻量的工作流引擎,适合用于中小型项目和微服务架构中的流程编排,本文给大家介绍LiteFlow轻量级工... 目录1. LiteFlow 主要特点2. 工作流定义方式3. LiteFlow 流程示例4. LiteF

使用Python开发一个现代化屏幕取色器

《使用Python开发一个现代化屏幕取色器》在UI设计、网页开发等场景中,颜色拾取是高频需求,:本文主要介绍如何使用Python开发一个现代化屏幕取色器,有需要的小伙伴可以参考一下... 目录一、项目概述二、核心功能解析2.1 实时颜色追踪2.2 智能颜色显示三、效果展示四、实现步骤详解4.1 环境配置4.

使用jenv工具管理多个JDK版本的方法步骤

《使用jenv工具管理多个JDK版本的方法步骤》jenv是一个开源的Java环境管理工具,旨在帮助开发者在同一台机器上轻松管理和切换多个Java版本,:本文主要介绍使用jenv工具管理多个JD... 目录一、jenv到底是干啥的?二、jenv的核心功能(一)管理多个Java版本(二)支持插件扩展(三)环境隔

SQL中JOIN操作的条件使用总结与实践

《SQL中JOIN操作的条件使用总结与实践》在SQL查询中,JOIN操作是多表关联的核心工具,本文将从原理,场景和最佳实践三个方面总结JOIN条件的使用规则,希望可以帮助开发者精准控制查询逻辑... 目录一、ON与WHERE的本质区别二、场景化条件使用规则三、最佳实践建议1.优先使用ON条件2.WHERE用