网络编程
Node.js 网络编程详解
Node.js 提供了丰富的内置模块,用于构建网络应用。下面从 HTTP/HTTPS、WebSocket、TCP/UDP 以及 DNS 解析四个方面进行深入介绍。
一、HTTP/HTTPS
http 和 https 模块是 Node.js 核心模块,用于创建 HTTP 服务器和客户端。
1. 创建服务器(http.createServer)
const http = require("http");
const server = http.createServer((req, res) => {
// req: 请求对象,包含请求方法、URL、头部等
// res: 响应对象,用于发送响应
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("Hello World\n");
});
server.listen(3000, () => {
console.log("Server running at http://localhost:3000/");
});
req是http.IncomingMessage实例,可读取请求行、头部、数据。res是http.ServerResponse实例,用于设置状态码、头部并写入响应体。
2. 处理请求/响应对象
获取请求信息:
const { method, url, headers } = req;
let body = "";
req.on("data", chunk => {
body += chunk.toString();
});
req.on("end", () => {
console.log("请求体:", body);
});
设置响应:
res.statusCode = 404;
res.setHeader("X-Custom", "MyValue");
res.write("Partial content");
res.end(); // 结束响应
常用便捷方法:
res.writeHead(statusCode, statusMessage, headers):同时设置状态码和头部。res.end([data]):结束响应,可选最后发送数据。
解析请求体:对于 JSON 或表单数据,可使用中间件或手动解析。也可借助 express 等框架。
3. 创建客户端请求(http.request 和 http.get)
const http = require("http");
// 使用 http.request
const req = http.request(
{
hostname: "example.com",
port: 80,
path: "/",
method: "GET",
headers: { Accept: "application/json" },
},
res => {
console.log(`状态码: ${res.statusCode}`);
res.setEncoding("utf8");
res.on("data", chunk => {
console.log(chunk);
});
}
);
req.on("error", e => console.error(e));
req.end();
// 简化 GET: http.get
http.get("http://example.com", res => {
/* ... */
});
对于 HTTPS,使用 https.request,默认端口 443。
4. 代理、Keep-Alive、超时设置
- 代理:可设置
agent选项自定义 HTTP 代理。例如使用http.Agent管理连接池,或使用globalAgent。也可通过HttpsProxyAgent实现代理转发。
const { Agent } = require("http");
const agent = new Agent({ keepAlive: true, maxSockets: 10 });
const req = http.request({ host: "...", agent });
- Keep-Alive:默认
agent.keepAlive为false,需手动开启:
const keepAliveAgent = new http.Agent({ keepAlive: true });
http.request({ agent: keepAliveAgent, ... });
- 超时设置:
- 服务器端:
server.setTimeout(timeout, callback)或req.setTimeout(timeout, callback)。 - 客户端:
req.setTimeout(timeout, callback)或设置timeout选项(request的 options 中)。
- 服务器端:
// 服务器超时
server.setTimeout(5000, socket => {
console.log("请求超时");
socket.destroy();
});
// 客户端超时
req.setTimeout(3000, () => {
req.destroy();
console.error("请求超时");
});
二、WebSocket:ws 库集成与简单聊天
WebSocket 实现了全双工通信,适合实时应用。ws 是 Node.js 中流行的 WebSocket 库。
安装
npm install ws
服务器端(与 HTTP 服务器共享端口)
const http = require("http");
const WebSocket = require("ws");
const server = http.createServer((req, res) => {
if (req.url === "/" && req.method === "GET") {
res.end("WebSocket server running");
}
});
const wss = new WebSocket.Server({ server });
wss.on("connection", (ws, req) => {
console.log("客户端连接");
ws.on("message", message => {
console.log("收到: %s", message);
// 广播给所有客户端
wss.clients.forEach(client => {
if (client !== ws && client.readyState === WebSocket.OPEN) {
client.send(message);
}
});
});
ws.send("欢迎加入聊天室");
});
server.listen(8080);
客户端(浏览器或 Node.js)
const ws = new WebSocket("ws://localhost:8080");
ws.onopen = () => ws.send("Hello");
ws.onmessage = e => console.log("收到:", e.data);
功能扩展
- 心跳检测:使用定时器发送 ping/pong。
- 房间管理:维护
Set或Map存储客户端分组。
三、TCP/UDP
1. TCP 服务器与客户端(net 模块)
TCP 服务器:
const net = require("net");
const server = net.createServer(socket => {
console.log("客户端已连接");
socket.on("data", data => {
console.log(`收到: ${data}`);
socket.write("Echo: " + data);
});
socket.on("end", () => console.log("客户端断开"));
socket.write("欢迎\r\n");
});
server.listen(3000, () => console.log("TCP 服务器监听 3000"));
TCP 客户端:
const net = require("net");
const client = net.createConnection({ port: 3000 }, () => {
console.log("已连接");
client.write("Hello 服务器\r\n");
});
client.on("data", data => console.log(data.toString()));
client.on("end", () => console.log("服务器关闭连接"));
2. UDP 通信(dgram 模块)
UDP 无连接,适用于低延迟、丢包容忍的场景。
UDP 服务器:
const dgram = require("dgram");
const server = dgram.createSocket("udp4");
server.on("message", (msg, rinfo) => {
console.log(`收到来自 ${rinfo.address}:${rinfo.port} 的消息: ${msg}`);
server.send("已收到", rinfo.port, rinfo.address);
});
server.bind(41234, () => console.log("UDP 服务器启动 41234"));
UDP 客户端:
const dgram = require("dgram");
const client = dgram.createSocket("udp4");
client.send("Hello UDP", 41234, "localhost", err => {
if (err) console.error(err);
else console.log("消息已发送");
});
client.on("message", msg => console.log("服务端回复:", msg.toString()));
四、DNS 解析:dns.lookup vs dns.resolve
dns 模块提供域名解析功能。核心区别:
| 方法 | 底层 | 是否涉及系统 DNS 缓存 | 返回类型 | 适用场景 |
|---|---|---|---|---|
dns.lookup | 与 getaddrinfo 相同,依赖操作系统配置(/etc/hosts、系统 DNS) | 是 | 返回单个 IPv4/IPv6 地址(或第一项) | 网络连接,例如 net.createConnection 内部使用 |
dns.resolve | 直接使用 DNS 协议查询,不经过系统缓存 | 否 | 返回完整记录数组(可指定类型如 A、AAAA、MX 等) | 获取完整 DNS 记录,或编程式排查 |
示例
const dns = require("dns");
dns.lookup("example.com", (err, address, family) => {
console.log("lookup:", address); // 通常一个IP
});
dns.resolve4("example.com", (err, addresses) => {
console.log("resolve4:", addresses); // IP数组
});
dns.resolveMx("gmail.com", (err, addresses) => {
console.log("MX记录:", addresses);
});
选择建议:一般使用 dns.lookup 进行网络连接;若需要获取所有记录或特定类型(如 MX、TXT),使用 dns.resolve。
总结
| 模块/功能 | 核心用途 | 常用 API |
|---|---|---|
http / https | 构建 Web 服务器和客户端 | createServer, request, get, Agent |
ws | WebSocket 实时通信 | WebSocket.Server, ws.send |
net | TCP 流式通信 | createServer, createConnection |
dgram | UDP 数据报通信 | createSocket, send, bind |
dns | 域名解析 | lookup, resolve 系列 |
掌握这些模块,可以搭建各种网络应用,从简单的 HTTP 服务到复杂的实时聊天系统。推荐结合官方文档和实际项目练习,加深理解。
相关文章
文件系统
Node.js 的 fs 模块提供了与文件系统交互的 API,几乎涵盖了所有标准文件操作。它支持三种风格的 API:同步、回调式异步 和 Promise 式异步。下面详细介绍这些 API 的选择策略、流式读写、文件监视以及常用操作。
缓冲区
Buffer 是 Node.js 全局对象,用于处理二进制数据流(如文件、网络数据)。在 ES6 引入 TypedArray 之前,Buffer 是 Node.js 处理二进制的主要方式;现在 Buffer 实现了 Uint8Arra…
路径处理
path 模块提供了用于处理和转换文件路径的实用工具。它是 Node.js 核心模块,无需安装即可直接使用。由于不同操作系统(Windows、Linux、macOS)的路径分隔符不同(Windows 使用反斜杠 \,POSIX 使用正…
进程与子进程
Node.js 在单个进程中运行,但通过 process 对象、child_process 模块及 worker_threads 模块提供了对进程的精细控制以及多进程/多线程能力。下面从三个方面展开。
流
流是 Node.js 中处理有序数据的抽象接口,用于以连续方式异步读取或写入数据。它们特别适合处理大文件、网络通信或任何可能无限产生的数据。Node.js 内置的 stream 模块提供了四种基本流类型,以及用于组合和错误处理的工具函数。
其他常用模块
以下是 Node.js 中几个重要内置模块的详细介绍,涵盖事件触发器、定时器、加密、压缩、操作系统信息和实用工具。