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

基于Socket、线程与Mutex的C#项目中CSV文件修改失效求助

问题描述

我是Luís,正在开发ServiMoto公司的移动服务管理客户端/服务器系统,服务涵盖园林检查、消防干预、邮政配送及披萨外卖。该系统支持骑手客户端连接服务器接收任务、更新任务状态及请求新任务,服务器通过C# Socket实现,利用Mutex保证CSV文件的独占访问,用于记录已分配任务与客户端信息。

当前遇到的问题:调用UpdateCompletedTask方法标记任务完成时,CSV文件始终无变化,多次修改该方法仍未解决,恳请技术帮助。

核心代码

Server类

// Object Mutex to ensure exclusive access to CSV files
static Mutex mutex = new Mutex();

// Method to update the CSV file with the completion of a task
static void UpdateCompletedTask(string fileName, string taskId)
{
    // Locks the mutex to ensure exclusive access
    mutex.WaitOne();
    try
    {
        string[] lines = File.ReadAllLines(fileName);
        for (int i = 0; i < lines.Length; i++)
        {
            if (lines[i].StartsWith(taskId))
            {
                // Replaces "in progress" with "completed" only if "in progress" is present
                if (lines[i].Contains("in progress"))
                {
                    lines[i] = lines[i].Replace("in progress", "completed");
                }
                break;
            }
        }
        File.WriteAllLines(fileName, lines);
    }
    finally
    {
        // Releases the mutex
        mutex.ReleaseMutex();
    }
}

// Method to assign a new task to the client and update the corresponding CSV file
static void AllocateNewTask(string fileName, string clientId)
{
    // Locks the mutex to ensure exclusive access
    mutex.WaitOne();
    try
    {
        // Logic to assign a new task to the client and update the CSV file
        // For example, it may involve reading the file to find an available task and updating its status
    }
    finally
    {
        // Releases the mutex
        mutex.ReleaseMutex();
    }
}

// Server IP address and port
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
int port = 8888;

// Starts the server and listens for connections
server = new TcpListener(ipAddress, port);
server.Start();

Console.WriteLine("Server started...");

// Accepts client connection
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Client connected!");

// Prepares network streams
NetworkStream stream = client.GetStream();
byte[] data = new byte[256];
StringBuilder response = new StringBuilder();

int bytesRead;

// Reads data received from the client
while ((bytesRead = stream.Read(data, 0, data.Length)) != 0)
{
    response.Append(Encoding.ASCII.GetString(data, 0, bytesRead));
    Console.WriteLine("Received message: {0}", response.ToString());

    // Checks the type of received message
    if (response.ToString().StartsWith("CONNECT"))
    {
        // Responds with success
        byte[] msg = Encoding.ASCII.GetBytes("100 OK");
        stream.Write(msg, 0, msg.Length);
        Console.WriteLine("Response sent: 100 OK");
    }
    else if (response.ToString().StartsWith("TASK_COMPLETE"))
    {
        // Extracts the ID of the completed task
        string completedTaskId = response.ToString().Substring("TASK_COMPLETE".Length).Trim();
        // Updates the corresponding CSV file
        UpdateCompletedTask("Service_A.csv", completedTaskId);
        // Responds with task completion confirmation
        byte[] msg = Encoding.ASCII.GetBytes("TASK_COMPLETED");
        stream.Write(msg, 0, msg.Length);
        Console.WriteLine("Response sent: TASK_COMPLETED");
    }
    else if (response.ToString() == "REQUEST_TASK")
    {
        // Logic to assign a new task to the client and update the CSV file
        // Here you can call the AllocateNewTask() method to assign the new task
    }
    else if (response.ToString() == "QUIT")
    {
        // Responds with connection closure
        byte[] msg = Encoding.ASCII.GetBytes("400 BYE");
        stream.Write(msg, 0, msg.Length);
        Console.WriteLine("Response sent: 400 BYE");

        // Closes the connection
        client.Close();
        break;
    }
    else
    {
        // Responds with error
        byte[] msg = Encoding.ASCII.GetBytes("ERROR");
        stream.Write(msg, 0, msg.Length);
        Console.WriteLine("Response sent: ERROR");
    }

    // Clears the StringBuilder for the next message
    response.Clear();
}

客户端类

// Server IP address and port
string serverIp = "127.0.0.1";
int port = 8888;

// Creates an instance of the TCP client
TcpClient client = new TcpClient(serverIp, port);
Console.WriteLine("Connected to server...");

// Prepares network streams
NetworkStream stream = client.GetStream();
byte[] data = new byte[256];
string response = string.Empty;

Console.WriteLine("Enter your Client ID: ");
string clientId = Console.ReadLine();

// Sends connection message
string connectMessage = "CONNECT";
byte[] connectMsg = Encoding.ASCII.GetBytes(connectMessage);
stream.Write(connectMsg, 0, connectMsg.Length);
Console.WriteLine("Message sent: {0}", connectMessage);

// Reads the server's response
int bytesReceived = stream.Read(data, 0, data.Length);
response = Encoding.ASCII.GetString(data, 0, bytesReceived);
Console.WriteLine("Response received: {0}", response);

while (true)
{
    Console.WriteLine("Choose an option:");
    Console.WriteLine("1. Complete task");
    Console.WriteLine("2. Request new task");
    Console.WriteLine("3. Quit");
    Console.Write("Option: ");
    string option = Console.ReadLine();

    switch (option)
    {
        case "1":
            // Sends task completion message
            Console.WriteLine("Enter the ID of the completed task: ");
            string completedTaskId = Console.ReadLine();
            string completionMessage = $"TASK_COMPLETE <{completedTaskId}>";
            byte[] completionMsg = Encoding.ASCII.GetBytes(completionMessage);
            stream.Write(completionMsg, 0, completionMsg.Length);
            Console.WriteLine("Message sent: {0}", completionMessage);

            // Reads the server's response
            int completionBytesReceived = stream.Read(data, 0, data.Length);
            response = Encoding.ASCII.GetString(data, 0, completionBytesReceived);
            Console.WriteLine("Response received: {0}", response);
            break;

        case "2":
            // Sends request for new task
            string requestMessage = "REQUEST_TASK";
            byte[] requestMsg = Encoding.ASCII.GetBytes(requestMessage);
            stream.Write(requestMsg, 0, requestMsg.Length);
            Console.WriteLine("Message sent: {0}", requestMessage);

            // Reads the server's response
            int requestBytesReceived = stream.Read(data, 0, data.Length);
            response = Encoding.ASCII.GetString(data, 0, requestBytesReceived);
            Console.WriteLine("Response received: {0}", response);
            break;

        case "3":
            // Sends quit message
            string quitMessage = "QUIT";
            byte[] quitMsg = Encoding.ASCII.GetBytes(quitMessage);
            stream.Write(quitMsg, 0, quitMsg.Length);
            Console.WriteLine("Message sent: {0}", quitMessage);

            // Reads the server's response
            int quitBytesReceived = stream.Read(data, 0, data.Length);
            response = Encoding.ASCII.GetString(data, 0, quitBytesReceived);
            Console.WriteLine("Response received: {0}", response);

            // Closes the connection and exits the loop
            client.Close();
            return;

        default:
            Console.WriteLine("Invalid option.");
            break;
    }
}
问题分析与解决方案

核心问题:任务ID提取不匹配

客户端发送的任务完成消息格式是TASK_COMPLETE <任务ID>,但服务器提取任务ID时仅去除了空格,保留了尖括号<>,导致传递给UpdateCompletedTask的taskId是带尖括号的字符串(比如<T1001>),而CSV文件中任务行是以纯任务ID开头(比如T1001, ..., in progress),lines[i].StartsWith(taskId)自然匹配失败,根本不会执行状态替换逻辑。

修复方案:修改服务器端任务ID提取逻辑

将服务器中提取任务ID的代码改为:

string completedTaskId = response.ToString().Substring("TASK_COMPLETE".Length).Trim().Trim('<', '>');

这样就能去掉尖括号,得到纯任务ID,确保和CSV中的任务ID格式一致。

其他排查点

  1. 文件路径验证:确认Service_A.csv存在于服务器程序的当前工作目录(可通过Directory.GetCurrentDirectory()输出验证),或者使用绝对路径避免路径问题。
  2. 任务状态检查:确保CSV中目标任务的状态确实是in progress,否则替换逻辑不会执行。
  3. 添加调试日志:在UpdateCompletedTask方法中添加日志,验证是否找到目标行、是否执行了替换:
static void UpdateCompletedTask(string fileName, string taskId)
{
    mutex.WaitOne();
    try
    {
        string[] lines = File.ReadAllLines(fileName);
        bool found = false;
        bool updated = false;
        for (int i = 0; i < lines.Length; i++)
        {
            if (lines[i].StartsWith(taskId))
            {
                found = true;
                if (lines[i].Contains("in progress"))
                {
                    lines[i] = lines[i].Replace("in progress", "completed");
                    updated = true;
                }
                break;
            }
        }
        File.WriteAllLines(fileName, lines);
        Console.WriteLine($"任务ID {taskId}:找到行={found},更新状态={updated}");
    }
    finally
    {
        mutex.ReleaseMutex();
    }
}
  1. Mutex使用验证:确保没有其他线程持有Mutex未释放,不过当前代码中finally块保证了释放,问题概率较低,但如果是多客户端场景,需确保每个操作都正确释放Mutex。

内容的提问来源于stack exchange,提问作者Luís Briga

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 22:32:34