C# TCP客户端连接安卓服务器遭拒,目标对接NodeMCU ESP8266
解决TCP客户端连接时“目标机器主动拒绝连接”的问题
首先,这个错误No connection could be made as the target machine actively refused it本质上是你的Windows客户端无法和安卓上的TCP服务器建立握手,大概率是服务器端没正确监听,或者网络/配置层面有问题,再加上你的客户端代码也有一些需要调整的地方,咱们一步步来解决:
一、先排查最常见的环境/服务器端问题
这些是最容易踩坑的点,先排除了再看代码:
- 确认安卓服务器的监听配置:
安卓端的TCP服务器必须监听0.0.0.0(允许所有IP访问)或者你的安卓设备在局域网内的实际IP(比如192.168.43.142),绝对不能只监听127.0.0.1(只能本地访问)。另外要确认服务器确实在你指定的端口监听——80端口经常被HTTP服务占用,建议换个不常用的端口比如8888试试,避免端口冲突。 - 检查网络连通性:
确保你的Windows电脑和安卓设备在同一局域网(比如连同一个WiFi,或者安卓开热点Windows连上去)。先在Windows的命令行里ping安卓的IP:ping 192.168.43.142,如果ping不通,说明网络本身有问题,先解决网络连通。 - 防火墙/安全软件拦截:
关闭Windows的防火墙(或者给你的窗体应用添加允许联网的规则),同时关闭安卓端的防火墙/安全软件,防止它们拦截TCP连接。 - 确认服务器正在运行:
安卓端的TCP服务器应用必须处于前台运行状态,有些安卓系统会后台杀进程,导致服务器停止监听。
二、修正你的C#客户端代码中的问题
你的代码基于微软的示例,但有几个不适合Windows窗体应用的地方,调整后能避免很多潜在问题:
1. 避免使用static Socket和全局状态
你把client、remoteEP等都声明为static,在窗体应用里容易出现生命周期混乱(比如多次点击连接按钮会重复操作同一个Socket)。建议把这些实例变量放到Form类的非static成员里。
2. 使用专门的状态类代替Form作为Receive的状态对象
用Form实例作为异步回调的状态对象很容易引发线程问题(因为WinForm控件只能在UI线程操作),应该创建一个单独的StateObject类来保存Socket和缓冲区。
3. 正确处理ManualResetEvent的重置
每次异步操作前要重置ManualResetEvent,否则第一次操作后事件一直处于触发状态,后续操作会直接跳过等待。
4. 断开连接时先判断Socket状态
避免在Socket未连接时调用Shutdown/Close,引发异常。
修正后的代码
namespace nodemcu_connection_test { public partial class Form1 : Form { // 非static的客户端Socket,避免全局状态混乱 private Socket _clientSocket = null; private const int BufferSize = 256; private const int Port = 8888; // 建议换个非80的端口 private readonly string _serverIp = "192.168.43.142"; private readonly IPEndPoint _remoteEP; // ManualResetEvent实例,每次使用前要重置 private readonly ManualResetEvent _connectDone = new ManualResetEvent(false); private readonly ManualResetEvent _sendDone = new ManualResetEvent(false); private readonly ManualResetEvent _receiveDone = new ManualResetEvent(false); private string _response = string.Empty; public Form1() { InitializeComponent(); _remoteEP = new IPEndPoint(IPAddress.Parse(_serverIp), Port); } private void connect_Click(object sender, EventArgs e) { StartClient(); } private void disconnect_Click(object sender, EventArgs e) { // 先判断Socket是否已连接,再释放资源 if (_clientSocket != null && _clientSocket.Connected) { try { _clientSocket.Shutdown(SocketShutdown.Both); } catch { // 忽略关闭时的异常 } _clientSocket.Close(); _clientSocket = null; MessageBox.Show("已断开连接"); } } private void stopreceive_Click(object sender, EventArgs e) { if (_clientSocket != null && _clientSocket.Connected) { Send("READSTOP"); } } private void startreceive_Click(object sender, EventArgs e) { if (_clientSocket != null && _clientSocket.Connected) { Send("READSTART"); Receive(); // 更新UI要回到UI线程,避免跨线程异常 Invoke((Action)(() => { textBox1.Text += _response + "\n"; })); } } private void StartClient() { try { // 先关闭旧的Socket(如果存在) disconnect_Click(null, null); // 创建新的TCP Socket _clientSocket = new Socket(IPAddress.Parse(_serverIp).AddressFamily, SocketType.Stream, ProtocolType.Tcp); // 重置连接事件 _connectDone.Reset(); // 开始异步连接 _clientSocket.BeginConnect(_remoteEP, ConnectCallback, _clientSocket); // 等待连接完成(设置5秒超时,避免无限等待) if (_connectDone.WaitOne(5000)) { MessageBox.Show("连接成功"); } else { MessageBox.Show("连接超时"); _clientSocket.Close(); _clientSocket = null; } } catch (Exception ex) { MessageBox.Show($"连接失败:{ex.Message}"); } } private void ConnectCallback(IAsyncResult ar) { try { Socket client = (Socket)ar.AsyncState; client.EndConnect(ar); Console.WriteLine("Socket connected to {0}", client.RemoteEndPoint.ToString()); _connectDone.Set(); } catch (Exception ex) { MessageBox.Show($"连接回调异常:{ex.Message}"); _connectDone.Set(); // 即使失败也要触发事件,避免死等 } } private void Receive() { try { if (_clientSocket == null || !_clientSocket.Connected) return; // 使用专门的状态对象 StateObject state = new StateObject(); state.WorkSocket = _clientSocket; _receiveDone.Reset(); _clientSocket.BeginReceive(state.Buffer, 0, BufferSize, 0, ReceiveCallback, state); _receiveDone.WaitOne(); } catch (Exception ex) { MessageBox.Show($"接收启动失败:{ex.Message}"); } } private void ReceiveCallback(IAsyncResult ar) { try { StateObject state = (StateObject)ar.AsyncState; Socket client = state.WorkSocket; int bytesRead = client.EndReceive(ar); if (bytesRead > 0) { state.Sb.Append(Encoding.ASCII.GetString(state.Buffer, 0, bytesRead)); // 继续接收剩余数据 client.BeginReceive(state.Buffer, 0, BufferSize, 0, ReceiveCallback, state); } else { if (state.Sb.Length > 0) { _response = state.Sb.ToString(); } _receiveDone.Set(); } } catch (Exception ex) { MessageBox.Show($"接收回调异常:{ex.Message}"); _receiveDone.Set(); } } private void Send(string data) { try { if (_clientSocket == null || !_clientSocket.Connected) return; byte[] byteData = Encoding.ASCII.GetBytes(data); _sendDone.Reset(); _clientSocket.BeginSend(byteData, 0, byteData.Length, 0, SendCallback, _clientSocket); _sendDone.WaitOne(); } catch (Exception ex) { MessageBox.Show($"发送失败:{ex.Message}"); } } private void SendCallback(IAsyncResult ar) { try { Socket client = (Socket)ar.AsyncState; int bytesSent = client.EndSend(ar); Console.WriteLine("Sent {0} bytes to server.", bytesSent); _sendDone.Set(); } catch (Exception ex) { MessageBox.Show($"发送回调异常:{ex.Message}"); _sendDone.Set(); } } // 专门的异步操作状态类,避免直接用Form实例引发线程问题 private class StateObject { public Socket WorkSocket { get; set; } = null; public byte[] Buffer { get; set; } = new byte[BufferSize]; public StringBuilder Sb { get; set; } = new StringBuilder(); } } }
三、针对NodeMCU(ESP8266)的额外注意事项
等你搞定安卓服务器的测试后,切换到NodeMCU时还要注意:
- NodeMCU的TCP服务器要监听
WiFi.localIP()对应的地址,或者0.0.0.0(允许所有IP访问) - 确保NodeMCU和Windows在同一局域网,并且NodeMCU的WiFi连接正常
- NodeMCU的端口不要被其他设备占用,建议用
8888、9999这类非知名端口 - 查看NodeMCU的串口输出,确认服务器是否正常启动并监听指定端口
内容的提问来源于stack exchange,提问作者Venkatesh Shiga
相关产品推荐
相关产品推荐

