如何将本地TCP/IP服务器收到的响应返回给ControllerFunction?
解决TCP服务器消息传递给控制器方法的问题
你的问题本质是要搞定跨线程的数据同步:后台跑的TCP监听线程收到仓储系统的消息后,怎么把消息传给主线程的ControllerFunction,还要让主线程等着,直到消息收到再返回。当前代码里后台线程的clientMessage是局部变量,主线程发完消息就直接返回,完全没等回复,肯定拿不到正确结果。
下面是修改后的完整实现,我给你加了线程同步和安全存储的逻辑:
using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; public class WarehouseTcpHandler { // 替换成你的本地监听IP和端口 private readonly string _localIp = "127.0.0.1"; private readonly int _localPort = 8888; // 替换成仓储系统的IP和端口 private readonly string _warehouseIp = "仓储系统IP地址"; private readonly int _warehousePort = 仓储系统端口号; private Thread _listenerThread; private TcpListener _tcpListener; // 标记服务器是否已启动,避免重复开线程 private bool _isServerRunning; // 用于通知主线程"消息已收到"的同步信号 private readonly ManualResetEventSlim _messageReceivedSignal = new ManualResetEventSlim(false); // 存储收到的消息,用锁保证多线程读写安全 private string _receivedMessage; private readonly object _messageLock = new object(); public void StartLocalServer() { if (_isServerRunning) return; _listenerThread = new Thread(ListenForWarehouseResponses) { IsBackground = true, Name = "WarehouseTcpListener" }; _listenerThread.Start(); _isServerRunning = true; Console.WriteLine("本地TCP服务器已启动,等待仓储系统回复..."); } private void ListenForWarehouseResponses() { try { _tcpListener = new TcpListener(IPAddress.Parse(_localIp), _localPort); _tcpListener.Start(); var buffer = new byte[1024]; while (_isServerRunning) { // 等待仓储系统的连接 using var client = _tcpListener.AcceptTcpClient(); using var stream = client.GetStream(); int bytesRead; // 读取流中的数据 while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0) { var incomingData = new byte[bytesRead]; Array.Copy(buffer, incomingData, bytesRead); var message = Encoding.ASCII.GetString(incomingData); // 线程安全地更新收到的消息 lock (_messageLock) { _receivedMessage = message; } // 发信号告诉主线程:消息到了! _messageReceivedSignal.Set(); } } } catch (SocketException ex) { Console.WriteLine($"TCP监听异常: {ex.Message}"); _isServerRunning = false; } } public string ControllerFunction() { // 重置状态,准备接收新的消息 _messageReceivedSignal.Reset(); lock (_messageLock) { _receivedMessage = null; } // 启动本地服务器(如果还没启动) StartLocalServer(); // 向仓储系统发送消息 SendMessageToWarehouse("a message"); // 等待仓储系统回复,设置30秒超时,防止无限阻塞 if (_messageReceivedSignal.Wait(TimeSpan.FromSeconds(30))) { lock (_messageLock) { return _receivedMessage; } } else { throw new TimeoutException("超过30秒未收到仓储系统的回复,请检查连接"); } } private void SendMessageToWarehouse(string message) { try { using var client = new TcpClient(_warehouseIp, _warehousePort); using var stream = client.GetStream(); var data = Encoding.ASCII.GetBytes(message); stream.Write(data, 0, data.Length); Console.WriteLine($"已向仓储系统发送消息: {message}"); } catch (SocketException ex) { throw new InvalidOperationException("无法连接到仓储系统服务器", ex); } } }
关键逻辑说明:
ManualResetEventSlim同步信号:这是主线程和后台监听线程的"通信工具"。后台线程收到消息后调用Set()触发信号,主线程用Wait()等着,直到信号触发或者超时。- 线程安全的消息存储:用
lock和私有锁对象_messageLock保护_receivedMessage,避免多线程同时读写导致的数据错乱。 - 服务器启动控制:加了
_isServerRunning标志,防止多次调用ControllerFunction时重复启动监听线程。 - 超时机制:
Wait(30秒)避免主线程无限等待,万一仓储系统没响应,也能及时抛出异常提示。
注意事项:
- 如果是在ASP.NET这类Web应用中使用,要注意后台线程的生命周期,避免应用池回收导致线程终止。
- 可以根据实际业务调整超时时间,比如改成10秒或者60秒。
- 要确保
_warehouseIp和_warehousePort配置正确,否则发消息会失败。
内容的提问来源于stack exchange,提问作者Mark Baijens
相关产品推荐
相关产品推荐

