读取文本文件后Socket连接断开,如何维持TCP长连接?
问题描述
我开发的TCP服务端需要读取文本文件并返回响应给客户端,但调用文件读取函数后Socket会断开连接(未调用该函数时连接可正常保持),希望维持连接并按需读取文件。
相关代码
等待客户端连接的监听器代码
static void Main(string[] args) { IPAddress ipAddr = IPAddress.Parse(args[1]); TcpListener listener = new TcpListener(ipAddr, Int32.Parse(args[2])); listener.Start(); Console.WriteLine("Waiting for a connection."); TcpClient client = listener.AcceptTcpClient(); Console.WriteLine("Client accepted."); while (true) { NetworkStream stream = client.GetStream(); StreamReader sr = new StreamReader(client.GetStream()); StreamWriter sw = new StreamWriter(client.GetStream()); try { if (stream.DataAvailable) { byte[] buffer = new byte[1024]; stream.Read(buffer, 0, buffer.Length); int recv = 0; foreach (byte b in buffer) { if (b != 0) { recv++; } } string request = Encoding.UTF8.GetString(buffer, 0, recv); Console.WriteLine("request received: " + request); if (request != null) { string response = null; response = apiQueryAndReponse(request, args[0]); if (response != null) { byte[] byData = Encoding.ASCII.GetBytes(response); stream.Write(byData, 0, byData.Length); stream.Flush(); } } } } catch (Exception e) { Console.WriteLine("Something went wrong."); Console.WriteLine(e.Message.ToString()); //sw.WriteLine(e.ToString()); } } }
获取并返回响应的代码
private static string apiQueryAndReponse(string rec, String stagingfilepath) { String response = null; if (rec.Contains("GetTesterInfo")) { response = getLatestStatusOK("GetTesterInfo", stagingfilepath); if (response != null) { Console.WriteLine("Response: " + response + "," + fileline + "\n"); fileline++; } } return response; }
读取文本文件并获取响应的代码
private static String getLatestStatusOK(String key, String filedir) { using (var fs = new FileStream(filedir, FileMode.Open, FileAccess.Read)) { using (var sr = new StreamReader(fs, Encoding.UTF8)) { while ((stagingfiledata = sr.ReadLine()) != null) { try { if (stagingfiledata.Contains(key)) { String[] data = stagingfiledata.Split(","); response = data[2]; } } catch (Exception exp) { Console.WriteLine("err message:" + exp.Message); } } } } return response; }
解决方案
1. 修复网络流重复创建问题
循环内反复创建NetworkStream、StreamReader和StreamWriter会导致底层流被多次包装,引发连接异常。需将这些对象移到循环外复用:
static void Main(string[] args) { IPAddress ipAddr = IPAddress.Parse(args[1]); TcpListener listener = new TcpListener(ipAddr, Int32.Parse(args[2])); listener.Start(); Console.WriteLine("Waiting for a connection."); // 使用using自动释放资源 using (TcpClient client = listener.AcceptTcpClient()) { Console.WriteLine("Client accepted."); using (NetworkStream stream = client.GetStream()) using (StreamReader sr = new StreamReader(stream, Encoding.UTF8)) using (StreamWriter sw = new StreamWriter(stream, Encoding.ASCII) { AutoFlush = true }) { while (true) { try { if (stream.DataAvailable) { byte[] buffer = new byte[1024]; // 直接用Read方法返回的实际读取长度,无需遍历非0字节 int recv = stream.Read(buffer, 0, buffer.Length); string request = Encoding.UTF8.GetString(buffer, 0, recv); Console.WriteLine("request received: " + request); if (!string.IsNullOrEmpty(request)) { string response = apiQueryAndReponse(request, args[0]); if (!string.IsNullOrEmpty(response)) { sw.Write(response); } } } // 添加短暂延迟避免CPU空转 Thread.Sleep(10); } catch (Exception e) { Console.WriteLine("Something went wrong."); Console.WriteLine(e.Message.ToString()); break; // 捕获异常后退出循环,避免无限报错 } } } } }
2. 修复文件读取函数的变量未定义问题
getLatestStatusOK中stagingfiledata和response未在函数内定义,需补充定义并添加数组越界检查:
private static String getLatestStatusOK(String key, String filedir) { string response = null; string stagingfiledata; using (var fs = new FileStream(filedir, FileMode.Open, FileAccess.Read)) { using (var sr = new StreamReader(fs, Encoding.UTF8)) { while ((stagingfiledata = sr.ReadLine()) != null) { try { if (stagingfiledata.Contains(key)) { String[] data = stagingfiledata.Split(","); // 检查数组长度,避免索引越界异常 if (data.Length >= 3) { response = data[2]; } } } catch (Exception exp) { Console.WriteLine("err message:" + exp.Message); } } } } return response; }
3. 避免文件读取阻塞连接
同步读取大文件会导致服务端无法及时响应客户端,建议改用异步文件读取:
private static async Task<String> getLatestStatusOKAsync(String key, String filedir) { string response = null; string stagingfiledata; using (var fs = new FileStream(filedir, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true)) using (var sr = new StreamReader(fs, Encoding.UTF8)) { while ((stagingfiledata = await sr.ReadLineAsync()) != null) { try { if (stagingfiledata.Contains(key)) { String[] data = stagingfiledata.Split(","); if (data.Length >= 3) { response = data[2]; } } } catch (Exception exp) { Console.WriteLine("err message:" + exp.Message); } } } return response; }
对应的调用函数也需改为异步:
private static async Task<string> apiQueryAndReponseAsync(string rec, String stagingfilepath) { String response = null; if (rec.Contains("GetTesterInfo")) { response = await getLatestStatusOKAsync("GetTesterInfo", stagingfilepath); if (response != null) { Console.WriteLine("Response: " + response + "," + fileline + "\n"); fileline++; } } return response; } // Main改为异步入口 static async Task Main(string[] args) { // 其他代码不变,处理请求部分改为: string response = await apiQueryAndReponseAsync(request, args[0]); // ... }
4. 检查文件访问权限
确保服务端进程拥有目标文件的读取权限,避免因权限异常导致连接意外断开。
内容的提问来源于stack exchange,提问作者ShiHang Ng
相关产品推荐
相关产品推荐

