NodeJS如何关闭指定IP的连接?
Alright, let's tackle this problem step by step. Since you're working with a stateless REST API but need to terminate stream connections for a specific IP while leaving others intact, we can use a module-level storage mechanism (not a global variable) to track active connections and target them selectively.
Step 1: Track Active Connections by Client IP
First, we'll create a map within your route module to associate each client IP with its active stream response objects. This stays within the module's scope (no global pollution) and lets us look up connections by IP later.
// 模块内的连接追踪Map,仅当前路由模块可访问 const activeConnections = new Map(); // 辅助函数:根据IP获取所有活跃连接 function getConnectionsByIp(targetIp) { const matches = []; for (const [ip, resList] of activeConnections.entries()) { if (ip === targetIp) matches.push(...resList); } return matches; }
Step 2: Modify Your Stream Route to Track Connections
Update your existing stream endpoint to capture the client IP, normalize it (to handle IPv6-wrapped IPv4 addresses), and store the response object. We'll also add cleanup logic to remove connections when they close naturally.
/* STREAM - client */ stream.get('/myapicall/:file/:user/', function(req, res) { // 获取客户端IP,处理IPv6格式的IPv4地址(比如::ffff:159.65.87.45) const clientIp = req.client.remoteAddress; const normalizedIp = clientIp.startsWith('::ffff:') ? clientIp.slice(7) : clientIp; // 将当前响应对象加入对应IP的追踪列表 if (!activeConnections.has(normalizedIp)) { activeConnections.set(normalizedIp, []); } activeConnections.get(normalizedIp).push(res); // 连接关闭时清理追踪记录,防止内存泄漏 const cleanup = () => { const resList = activeConnections.get(normalizedIp); if (resList) { const index = resList.indexOf(res); if (index !== -1) { resList.splice(index, 1); // 如果该IP没有活跃连接了,移除条目 if (resList.length === 0) activeConnections.delete(normalizedIp); } } }; res.on('finish', cleanup); res.on('close', cleanup); // 原有的流响应逻辑 try { res.write(fs.readFileSync('/tmp/myfie.m3u8')); // 如果是一次性文件传输,记得结束响应;如果是持续流,可根据需求调整 res.end(); } catch (err) { console.error('Stream error:', err); res.status(500).end('Internal Server Error'); cleanup(); // 出错时也要清理记录 } });
Step 3: Add the Kill Connection API Endpoint
Create a dedicated API endpoint to receive the target IP and terminate its active connections. This endpoint will look up the IP in our map, destroy the associated responses, and send a confirmation.
// Kill Connection API - 建议用POST/DELETE,这里用POST示例 stream.post('/kill-connection/:ip', function(req, res) { const targetIp = req.params.ip; const connections = getConnectionsByIp(targetIp); if (connections.length === 0) { return res.status(404).json({ message: `No active connections found for IP ${targetIp}` }); } // 逐个关闭连接 connections.forEach(conn => { if (!conn.finished) { conn.destroy(new Error('Connection terminated by admin')); } }); res.json({ message: `Successfully terminated ${connections.length} connections for IP ${targetIp}` }); });
Key Notes to Keep in Mind
- IP Normalization: Node.js often returns IPv4 addresses in IPv6 format (e.g.,
::ffff:159.65.87.45), so we strip the prefix to get the standard IPv4 address for accurate matching. - Memory Leak Prevention: Always clean up the map when connections close (via
finish/closeevents) to avoid holding onto unused response objects. - Security: Add authentication/authorization to the
/kill-connectionendpoint (e.g., API keys, session checks) to prevent unauthorized users from terminating connections. - Cluster Mode: If your app runs in a multi-process cluster, the module-level map won't work across processes. In that case, use a shared storage system like Redis to track connections globally.
内容的提问来源于stack exchange,提问作者Igor Petev

