// named-pipe-server.js const net = require('net'); const fs = require('fs'); const path = require('path'); const { EventEmitter } = require('events'); const async_hooks = require('async_hooks'); const { v4: uuidv4 } = require('uuid'); const DEFAULT_PIPE_PATH = process.platform === 'win32'? '\\\\.\\pipe\\rwlock' : '/tmp/rwlock.sock'; /** * 基于命名管道的读写锁服务器 * 提供跨进程的读写锁功能,支持多个客户端同时请求对同一资源的读锁或写锁 * 实现读写锁的基本语义: * 1. 多个读操作可以同时进行 * 2. 写操作是独占的,不允许同时进行读或其他写操作 * 3. 锁请求按先进先出(FIFO)方式处理 */ class NamedPipeLockServer extends EventEmitter { /** * 创建一个NamedPipeLockServer实例 * @param {string} pipePath - 命名管道路径,默认值根据操作系统确定 */ constructor(pipePath = DEFAULT_PIPE_PATH) { super(); this.pipePath = pipePath; this.server = null; this.locks = new Map(); // resource -> { readers: Set, writer: null, queue: [] } this.clients = new Map(); // clientId -> socket } /** * 启动服务器 * 创建并监听命名管道,处理客户端连接和消息 */ start() { // 确保管道文件不存在(Windows) if (process.platform === 'win32') { try { if (fs.existsSync(this.pipePath)) { fs.unlinkSync(this.pipePath); } } catch (error) { // 忽略错误,可能管道正在使用 } } this.server = net.createServer(socket => { const clientId = uuidv4(); socket.clientId = clientId; this.clients.set(clientId, socket); console.log(`Client connected: ${clientId}`); socket.on('data', data => { try { const messageStrs = data.toString().split('\n'); messageStrs.forEach(messageStr => { if (messageStr) { const message = JSON.parse(messageStr); this.handleMessage(clientId, message); } }); // const message = JSON.parse(); // this.handleMessage(clientId, message); } catch (error) { console.error('Error parsing message:', error); this.sendError(clientId, 'Invalid message format'); } }); socket.on('close', () => { this.handleClientDisconnect(clientId); this.clients.delete(clientId); console.log(`Client disconnected: ${clientId}`); }); socket.on('error', error => { console.error(`Client error (${clientId}):`, error); this.handleClientDisconnect(clientId); this.clients.delete(clientId); }); }); // 启动命名管道服务器 this.server.listen(this.pipePath, () => { console.log(`Lock server listening on named pipe: ${this.pipePath}`); }); this.server.on('error', error => { console.error('Server error:', error); }); } /** * 处理来自客户端的消息 * @param {string} clientId - 客户端标识符 * @param {Object} message - 消息对象 */ handleMessage(clientId, message) { const { type, resource, requestId } = message; if (!this.locks.has(resource)) { this.locks.set(resource, { readers: new Set(), writer: null, queue: [] }); } const lock = this.locks.get(resource); switch (type) { case 'readLock': this.handleReadLock(clientId, resource, requestId, lock); break; case 'writeLock': this.handleWriteLock(clientId, resource, requestId, lock); break; case 'unlock': this.handleUnlock(clientId, resource, lock); break; default: this.sendError(clientId, `Unknown message type: ${type}`); } } /** * 处理读锁请求 * @param {string} clientId - 客户端标识符 * @param {string} resource - 资源名称 * @param {string} requestId - 请求ID * @param {Object} lock - 锁对象 */ handleReadLock(clientId, resource, requestId, lock) { if (!lock.writer) { // 可以立即获取读锁 lock.readers.add(clientId); this.sendToClient(clientId, { type: 'lockGranted', requestId, resource, lockType: 'read' }); console.log(`Read lock granted to ${clientId} for ${resource}`); } else { // 加入等待队列 lock.queue.push({ clientId, type: 'read', requestId }); console.log(`Read lock queued for ${clientId} for ${resource}`); } } /** * 处理写锁请求 * @param {string} clientId - 客户端标识符 * @param {string} resource - 资源名称 * @param {string} requestId - 请求ID * @param {Object} lock - 锁对象 */ handleWriteLock(clientId, resource, requestId, lock) { if (lock.readers.size === 0 && !lock.writer) { // 可以立即获取写锁 lock.writer = clientId; this.sendToClient(clientId, { type: 'lockGranted', requestId, resource, lockType: 'write' }); console.log(`Write lock granted to ${clientId} for ${resource}`); } else { // 加入等待队列 lock.queue.push({ clientId, type: 'write', requestId }); console.log(`Write lock queued for ${clientId} for ${resource}`); } } /** * 处理解锁请求 * @param {string} clientId - 客户端标识符 * @param {string} resource - 资源名称 * @param {Object} lock - 锁对象 */ handleUnlock(clientId, resource, lock) { let released = false; // 移除读锁 if (lock.readers.has(clientId)) { lock.readers.delete(clientId); released = true; console.log(`Read lock released by ${clientId} for ${resource}`); } // 移除写锁 if (lock.writer === clientId) { lock.writer = null; released = true; console.log(`Write lock released by ${clientId} for ${resource}`); } if (released) { // 处理等待队列 this.processQueue(resource, lock); } } /** * 处理等待队列中的锁请求 * 根据读写锁规则,尽可能多地授权锁请求 * @param {string} resource - 资源名称 * @param {Object} lock - 锁对象 */ processQueue(resource, lock) { const granted = []; for (let i = 0; i < lock.queue.length; i++) { const request = lock.queue[i]; if (request.type === 'read') { if (!lock.writer) { // 可以授予读锁 lock.readers.add(request.clientId); this.sendToClient(request.clientId, { type: 'lockGranted', requestId: request.requestId, resource, lockType: 'read' }); granted.push(i); console.log(`Queued read lock granted to ${request.clientId} for ${resource}`); } else { // 有写锁等待,读锁必须等待 break; } } else { // write if (lock.readers.size === 0 && !lock.writer) { // 可以授予写锁 lock.writer = request.clientId; this.sendToClient(request.clientId, { type: 'lockGranted', requestId: request.requestId, resource, lockType: 'write' }); granted.push(i); console.log(`Queued write lock granted to ${request.clientId} for ${resource}`); } else { // 写锁必须等待前面的锁释放 break; } } } // 移除已处理的请求 if (granted.length > 0) { lock.queue = lock.queue.filter((_, index) => !granted.includes(index)); } } /** * 处理客户端断开连接 * 释放该客户端持有的所有锁,并处理相关队列 * @param {string} clientId - 客户端标识符 */ handleClientDisconnect(clientId) { console.log(`Processing disconnect for client: ${clientId}`); // 释放该客户端持有的所有锁 for (const [resource, lock] of this.locks) { let released = false; if (lock.readers.has(clientId)) { lock.readers.delete(clientId); released = true; } if (lock.writer === clientId) { lock.writer = null; released = true; } // 如果释放了锁,重新处理队列 if (released) { this.processQueue(resource, lock); } } } /** * 向指定客户端发送消息 * @param {string} clientId - 客户端标识符 * @param {Object} message - 要发送的消息对象 */ sendToClient(clientId, message) { const socket = this.clients.get(clientId); if (socket && !socket.destroyed) { try { socket.write(JSON.stringify(message)); } catch (error) { console.error(`Error sending to client ${clientId}:`, error); } } } /** * 向客户端发送错误消息 * @param {string} clientId - 客户端标识符 * @param {string} errorMessage - 错误信息 */ sendError(clientId, errorMessage) { this.sendToClient(clientId, { type: 'error', message: errorMessage }); } /** * 停止服务器 */ stop() { if (this.server) { this.server.close(); console.log('Lock server stopped'); } } } // // 启动服务器 // const pipePath = process.platform === 'win32' // ? '\\\\.\\pipe\\rwlock-server' // : '/tmp/rwlock.sock'; // const server = new NamedPipeLockServer(pipePath); // server.start(); // // 优雅关闭 // process.on('SIGINT', () => { // console.log('Shutting down lock server...'); // server.stop(); // process.exit(0); // }); // process.on('SIGTERM', () => { // console.log('Shutting down lock server...'); // server.stop(); // process.exit(0); // }); module.exports = NamedPipeLockServer;