You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

读取文本文件后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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 15:45:23