TCPListener客户端断开时抛异常致其他客户端崩溃问题排查
TCP客户端断开导致Listener崩溃问题修复
问题描述
当TCP客户端断开连接时,TCPListener抛出未处理异常;现有两个客户端每秒发送随机消息,关闭其中一个客户端后,Listener触发错误,导致另一个客户端也报错并关闭控制台应用。
异常信息
未处理的异常。System.IO.IOException: 无法从传输连接读取数据: 远程主机强迫关闭了一个现有的连接。 ---> System.Net.Sockets.SocketException (10054): 远程主机强迫关闭了一个现有的连接。 在 System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 count) --- 内部异常堆栈跟踪结束 --- 在 System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 count) 在 ConsoleApp2.Program.handle_connection(IAsyncResult result) 位置 C:\Users\ahmet\OneDrive\Desktop\new\ConsoleApp2\Program.cs:行 67 在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) --- 之前位置的堆栈跟踪结束 --- 在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) 在 System.Threading.Tasks.AwaitTaskContinuation.RunCallback(ContextCallback callback, Object state, Task& currentTask) --- 之前位置的堆栈跟踪结束 --- 在 System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_1(Object state) 在 System.Threading.ThreadPoolWorkQueue.Dispatch() 在 System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()
TCP服务端代码
using System; using System.Threading; using System.Collections.Concurrent; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Collections.Generic; namespace ConsoleApp2 { class Program { TcpListener server = new TcpListener(IPAddress.Any, 13000); static void Main(string[] args) { try { Program main = new Program(); main.server_start(); Console.ReadLine(); } catch (ArgumentNullException e) { Console.WriteLine("ArgumentNullException: {0}", e); } catch (SocketException e) { Console.WriteLine("SocketException: {0}", e); } } private void server_start() { try { server.Start(); } catch (ArgumentNullException e) { Console.WriteLine("ArgumentNullException: {0}", e); } catch (SocketException e) { Console.WriteLine("SocketException: {0}", e); } Console.WriteLine("服务器已启动。等待连接..."); accept_connection(); } private void accept_connection() { try { server.BeginAcceptTcpClient(handle_connection, server); } catch (ArgumentNullException e) { Console.WriteLine("ArgumentNullException: {0}", e); } catch (SocketException e) { Console.WriteLine("SocketException: {0}", e); } } private void handle_connection(IAsyncResult result) { try { Console.WriteLine("已连接..."); accept_connection(); TcpClient client = server.EndAcceptTcpClient(result); NetworkStream stream = client.GetStream(); Byte[] bytes = new Byte[256]; String data = null; int i; while ((i = stream.Read(bytes, 0, bytes.Length)) != 0) { data = System.Text.Encoding.ASCII.GetString(bytes, 0, i); Console.WriteLine("{0}", data); } } catch (ArgumentNullException e) { Console.WriteLine("ArgumentNullException: {0}", e); } catch (SocketException e) { Console.WriteLine("SocketException: {0}", e); } } } }
TCP客户端代码
using System; using System.Threading; using System.Collections.Concurrent; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Collections.Generic; namespace ConsoleApp2 { class Program { static TcpClient client = new TcpClient("127.0.0.1",13000); static List<string> messages = new List<string>(); public static readonly object locker = new object(); static void Main() { ThreadPool.QueueUserWorkItem(LoadMessages); Thread.Sleep(100); ThreadPool.QueueUserWorkItem(SendMessages); Console.ReadLine(); } static void LoadMessages(object state) { lock (locker) { messages.Add("Java"); messages.Add("C"); messages.Add("C++"); messages.Add("C#"); messages.Add("Python"); messages.Add("HTML"); messages.Add("CSS"); messages.Add("PHP"); messages.Add("HELLO"); } } static void SendMessages(object state) { while (true) { var random = new Random(); string message = messages[random.Next(messages.Count)]; Byte[] data = System.Text.Encoding.ASCII.GetBytes(message); NetworkStream stream = client.GetStream(); stream.Write(data, 0, data.Length); Console.WriteLine("消息已发送"); Thread.Sleep(1000); } } } }
尝试过的方法
尝试返回false,但提示BeginAcceptTcpClient()需要void类型。
解决方案
问题核心是handle_connection方法未捕获IOException,客户端强制断开时stream.Read抛出该异常,未处理导致程序崩溃;同时未正确关闭连接造成资源泄漏。修改后的服务端代码如下:
using System; using System.Threading; using System.Collections.Concurrent; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Collections.Generic; namespace ConsoleApp2 { class Program { TcpListener server = new TcpListener(IPAddress.Any, 13000); static void Main(string[] args) { try { Program main = new Program(); main.server_start(); Console.ReadLine(); } catch (ArgumentNullException e) { Console.WriteLine("ArgumentNullException: {0}", e); } catch (SocketException e) { Console.WriteLine("SocketException: {0}", e); } catch (Exception e) { Console.WriteLine("未处理异常: {0}", e); } } private void server_start() { try { server.Start(); } catch (ArgumentNullException e) { Console.WriteLine("ArgumentNullException: {0}", e); } catch (SocketException e) { Console.WriteLine("SocketException: {0}", e); } catch (Exception e) { Console.WriteLine("启动服务器失败: {0}", e); } Console.WriteLine("服务器已启动。等待连接..."); accept_connection(); } private void accept_connection() { try { server.BeginAcceptTcpClient(handle_connection, server); } catch (ArgumentNullException e) { Console.WriteLine("ArgumentNullException: {0}", e); } catch (SocketException e) { Console.WriteLine("SocketException: {0}", e); } catch (Exception e) { Console.WriteLine("接受连接失败: {0}", e); } } private void handle_connection(IAsyncResult result) { TcpClient client = null; NetworkStream stream = null; try { Console.WriteLine("已连接..."); // 提前监听新连接,避免阻塞 accept_connection(); client = server.EndAcceptTcpClient(result); stream = client.GetStream(); Byte[] bytes = new Byte[256]; String data = null; int i; while ((i = stream.Read(bytes, 0, bytes.Length)) != 0) { data = System.Text.Encoding.ASCII.GetString(bytes, 0, i); Console.WriteLine("收到消息: {0}", data); } } catch (ArgumentNullException e) { Console.WriteLine("ArgumentNullException: {0}", e); } catch (SocketException e) { Console.WriteLine("Socket异常(客户端断开): {0}", e); } catch (IOException e) { Console.WriteLine("IO异常(客户端断开): {0}", e); } catch (Exception e) { Console.WriteLine("处理连接时出错: {0}", e); } finally { // 确保资源被正确释放 stream?.Close(); client?.Close(); Console.WriteLine("连接已关闭"); } } } }
修改点说明
- 添加IOException捕获:直接捕获客户端断开时抛出的
IOException,避免未处理异常导致程序崩溃。 - 资源释放:使用
finally块确保TcpClient和NetworkStream被正确关闭,防止资源泄漏。 - 提前监听新连接:在获取客户端连接前调用
accept_connection(),确保服务器不会错过新的连接请求。 - 全局异常捕获:在
Main和server_start中添加通用Exception捕获,处理其他未预见的错误。
修改后,单个客户端断开只会触发对应连接的异常处理,不会影响服务器整体运行,其他客户端可正常通信。
内容的提问来源于stack exchange,提问作者Saul4Goodman
相关产品推荐
相关产品推荐

