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

C# TCP C/S程序校验客户端输入执行操作失效问题排查

C# TCP客户端/服务端应用问题修复

功能需求

使用 C# 开发客户端/服务端应用(client server app),需实现以下功能:

  • 客户端发送消息(client sends a msg)后,服务端将消息原样回传(server sends it back)给客户端
  • 服务端校验(check)客户端发送的内容并执行对应逻辑:比如客户端发送"chrome"时,服务端匹配成功后启动chrome.exe进程。

现存故障

代码运行时存在两个异常:

  • 客户端发送chrome指令时,服务端始终弹出客户端已断开连接提示(client disconnected message),进程启动、消息回传逻辑均未执行
  • 尝试将现有控制台程序转换为*Windows窗体应用(windows forms app)*时出现大量编译/运行错误,程序无法正常启动。

现有实现代码

服务端代码(server code)

using System;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Net;
using System.Text;

namespace consoleTcpServer {

    class Program {
        class ConnectionHandler {
            private Socket client;
            private NetworkStream ns;
            private StreamReader reader;
            private StreamWriter writer;
            private static int connections = 0;

            //The constructor take the accepted client as argument
            public ConnectionHandler(Socket client) {
                this.client = client;
            }

            public void HandleConnection() {

                try {
                    ns = new NetworkStream(client);
                    reader = new StreamReader(ns);
                    writer = new StreamWriter(ns);
                    connections++;
                    Console.WriteLine("New client accepted: {0} active   connections",
                        connections);
                    writer.WriteLine("Welcome to my server");
                    writer.Flush();
                    string input;
                    while ((input = reader.ReadLine()).Length != 0) {

                        if (input.Contains("chrome")) {
                            System.Diagnostics.Process.Start("chrome.exe", "www.google.com");
                        } else if (input.Contains("fox")) {
                            System.Diagnostics.Process.Start("firefox.exe", "www.facebook.com");
                        }

                        Console.WriteLine(input);
                        writer.WriteLine(input);
                        writer.Flush();
                    }

                    // ns.Close();
                    // client.Close();
                    connections--;
                    Console.WriteLine("Client disconnected: {0} active connections", connections);
                } catch (Exception) {
                    connections--;
                    Console.WriteLine("Client disconnected: {0} active   connections",
                        connections);

                }

            }

        }
        static void Main(string[] args) {
            Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
                ProtocolType.Tcp);
            IPEndPoint localEP = new IPEndPoint(IPAddress.Any, 9050);
            server.Bind(localEP);
            server.Listen(10);
            Console.WriteLine("Waiting for a client");

            while (true) {
                try {
                    Socket client = server.Accept();
                    ConnectionHandler handler = new ConnectionHandler(client);
                    Thread thread = new Thread(new ThreadStart(handler.HandleConnection));
                    thread.Start();

                } catch (Exception) {
                    Console.WriteLine("Connection failed ..");
                }
                //client.Close();
                //server.Shutdown();

            }

        }

    }
}

客户端代码(client code)

using System;
using System.Net;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using System.Text;

namespace consoleTcpClient {
    class Program {

        static void Main(string[] args) {
            //  Console.WriteLine("Hello World!");

            Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
                ProtocolType.Tcp);
            IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050);

            client.Connect(remoteEP);

            NetworkStream stream = new NetworkStream(client);
            StreamReader reader = new StreamReader(stream);
            StreamWriter writer = new StreamWriter(stream);

            String input = reader.ReadLine();
            Console.WriteLine(input);
            String line = null;

            while (true) {
                Console.Write("Enter Message for Server <Enter to  Stop >: ");
                line = Console.ReadLine();

                //writing for server
                writer.WriteLine(line);
                writer.Flush();

                if (line.Length != 0) {
                    line = "Echo: " + reader.ReadLine();
                    Console.WriteLine(line);
                }
            }
            // client.Close();

        }
    }
}

故障原因与修复方案

1. 发送chrome指令触发断连提示

核心原因有两个:

  • 读取循环存在空引用漏洞:服务端while ((input = reader.ReadLine()).Length != 0) 没有判断ReadLine()返回值,当TCP连接断开时ReadLine()会返回null,直接访问.Length会抛出空引用异常,进入catch块打印断连提示。
  • 进程启动逻辑无异常处理:大部分设备不会把Chrome、Firefox的路径加入系统环境变量,直接调用Process.Start("chrome.exe")会抛出“找不到文件”异常,同样会触发catch块的断连逻辑。

修复方式:

  • 修改读取循环判断逻辑,先校验ReadLine()返回值不为null再判断长度
  • 进程启动逻辑单独加try-catch,优先使用浏览器的默认安装路径,找不到路径时给客户端返回错误提示
  • 把资源释放逻辑移到finally块,确保连接断开时Socket、网络流能被正确释放,避免连接数统计错误。

修复后的服务端连接处理核心逻辑参考:

public void HandleConnection() {
    try {
        ns = new NetworkStream(client);
        reader = new StreamReader(ns);
        writer = new StreamWriter(ns);
        connections++;
        Console.WriteLine($"New client accepted: {connections} active connections");
        writer.WriteLine("Welcome to my server");
        writer.Flush();
        string input;
        // 先判断ReadLine返回值是否为null
        while ((input = reader.ReadLine()) != null && input.Length != 0) {
            try {
                if (input.Contains("chrome")) {
                    // 替换为设备上Chrome的实际路径,或通过注册表查找安装路径
                    System.Diagnostics.Process.Start(@"C:\Program Files\Google\Chrome\Application\chrome.exe", "www.google.com");
                } else if (input.Contains("fox")) {
                    System.Diagnostics.Process.Start(@"C:\Program Files\Mozilla Firefox\firefox.exe", "www.facebook.com");
                }
            }
            catch (Exception ex) {
                writer.WriteLine($"Execute command failed: {ex.Message}");
                writer.Flush();
                Console.WriteLine($"Command execute error: {ex.Message}");
                continue;
            }

            Console.WriteLine(input);
            writer.WriteLine(input);
            writer.Flush();
        }
    } catch (Exception ex) {
        Console.WriteLine($"Connection error: {ex.Message}");
    }
    finally {
        // 统一释放资源
        reader?.Close();
        writer?.Close();
        ns?.Close();
        client?.Close();
        connections--;
        Console.WriteLine($"Client disconnected: {connections} active connections");
    }
}

2. 控制台程序转WinForm报错

核心原因是控制台程序和WinForm程序的运行模型差异,修复时注意三点:

  • 不要把TCP监听、消息接收的阻塞逻辑放到UI线程:原有Accept()、ReadLine()都是阻塞方法,直接放到UI线程会导致界面假死,要把网络逻辑放到独立后台线程运行。
  • 跨线程更新UI必须用控件的Invoke方法:后台线程不能直接操作窗体上的文本框、标签等控件,否则会抛出跨线程访问异常。
  • 项目配置要匹配WinForm要求:给Main方法添加[STAThread]特性,添加System.Windows.Forms、System.Drawing程序集引用,将项目输出类型改为“Windows应用程序”,不要保留控制台的输入输出逻辑,所有日志、交互都通过窗体控件实现。

内容的提问来源于stack exchange,提问作者ektfaa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 01:18:49