如何实现C#服务器接收Node.js客户端命令及通信?
Hey there! 我看你正在搭建C# TCP服务器和Node.js客户端的通信链路,现有代码已经搭好了基础的流初始化框架,但还有变量命名一致性、消息收发逻辑、资源释放这些细节需要补全。我来帮你把整个实现流程梳理清楚,附上完整的可运行代码和关键注意事项:
1. 完善C# TCP服务器代码
首先修正你现有代码里的变量命名不一致问题(比如私有字段_controlStream和你后续写的controlStream),然后补充完整的连接监听、消息收发、异常处理和资源释放逻辑:
using System; using System.Net; using System.Net.Sockets; using System.IO; using System.Text; using System.Threading.Tasks; public class TcpServer { private TcpListener _listener; // 保持私有字段命名的一致性 private NetworkStream _controlStream; private StreamReader _controlReader; private StreamWriter _controlWriter; private string _clientIP; public void StartServer(int port) { _listener = new TcpListener(IPAddress.Any, port); _listener.Start(); Console.WriteLine($"TCP Server started, listening on port {port}"); // 异步接受客户端连接,支持多客户端接入 _ = AcceptClientsAsync(); } private async Task AcceptClientsAsync() { while (true) { try { var controlClient = await _listener.AcceptTcpClientAsync(); Console.WriteLine("New client connected"); // 单独开任务处理当前客户端,不阻塞后续连接 _ = HandleClientAsync(controlClient); } catch (Exception ex) { Console.WriteLine($"Failed to accept client: {ex.Message}"); break; } } } private async Task HandleClientAsync(TcpClient controlClient) { try { var remoteEndPoint = (IPEndPoint)controlClient.Client.RemoteEndPoint; _clientIP = remoteEndPoint.Address.ToString(); Console.WriteLine($"Client IP: {_clientIP}"); _controlStream = controlClient.GetStream(); // 指定UTF8编码保证跨语言编码一致,开启AutoFlush避免消息缓存 _controlReader = new StreamReader(_controlStream, Encoding.UTF8); _controlWriter = new StreamWriter(_controlStream, Encoding.UTF8) { AutoFlush = true }; // 循环接收客户端消息,直到连接断开 string receivedMsg; while ((receivedMsg = await _controlReader.ReadLineAsync()) != null) { Console.WriteLine($"Received from {_clientIP}: {receivedMsg}"); // 回复客户端消息 await _controlWriter.WriteLineAsync($"Server echo: {receivedMsg}"); } Console.WriteLine($"Client {_clientIP} disconnected"); } catch (Exception ex) { Console.WriteLine($"Error handling client {_clientIP}: {ex.Message}"); } finally { // 确保资源被正确释放,避免内存泄漏 _controlReader?.Dispose(); _controlWriter?.Dispose(); _controlStream?.Dispose(); controlClient?.Dispose(); } } } // 启动服务器示例 class Program { static void Main() { var server = new TcpServer(); server.StartServer(8888); Console.WriteLine("Press any key to stop server..."); Console.ReadKey(); } }
2. 配套Node.js客户端实现
对应C#服务器的消息格式(换行符分隔消息),用Node.js的net模块实现客户端,同时用readline模块提供命令行交互:
const net = require('net'); const readline = require('readline'); // 创建命令行交互实例 const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); // 连接到C#服务器 const client = new net.Socket(); client.connect(8888, 'localhost', () => { console.log('Successfully connected to C# server'); promptForMessage(); }); // 接收服务器回复 client.on('data', (data) => { console.log(`Server response: ${data.toString().trim()}`); promptForMessage(); }); // 处理连接关闭 client.on('close', () => { console.log('Connection to server closed'); rl.close(); }); // 处理网络错误 client.on('error', (err) => { console.log(`Network error: ${err.message}`); rl.close(); }); // 提示用户输入消息 function promptForMessage() { rl.question('Enter message to send (type "exit" to quit): ', (msg) => { if (msg.toLowerCase() === 'exit') { client.end(); rl.close(); return; } // 发送消息时添加换行符,匹配C#的ReadLine逻辑 client.write(`${msg}\n`); }); }
3. 关键注意事项
- 消息边界处理:TCP是流协议,我们用换行符
\n作为消息分隔符,对应C#的ReadLineAsync和Node.js的行读取逻辑,避免粘包问题;如果需要传输二进制数据,可以改用「消息长度前缀+内容」的格式。 - 编码一致性:全程统一使用UTF8编码,避免跨语言通信时出现乱码。
- 多客户端支持:C#服务器用异步任务单独处理每个客户端连接,不会阻塞后续客户端接入。
- 资源释放:C#中使用
Dispose释放流和客户端资源,Node.js中监听连接关闭事件清理资源,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Bing Feng
相关产品推荐
相关产品推荐

