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

C# Socket单对单通信改造为支持多客户端指定收信方的开发问题

多客户端Socket通信实现方案

核心调整逻辑

  • 新增线程安全的客户端管理容器:使用Dictionary<string, Socket>存储客户端唯一标识(IP+端口组合)与对应的Socket实例,替换原有单客户端Socket变量,操作字典时加锁避免多线程冲突
  • 拆分多线程职责:
    • 独立线程循环监听客户端连接请求,每成功接入一个客户端就存入管理字典,同时为该客户端启动专属的消息接收线程
    • 每个客户端的消息接收逻辑独立运行,互不阻塞,客户端断开连接时自动从管理字典中移除
  • 定向消息发送实现:约定服务端输入格式为[目标客户端标识] 消息内容,解析后匹配对应Socket发送,也可支持广播逻辑
  • 调整监听队列配置:将原有Listen(1)调整为Listen(10),支持最多10个客户端同时排队接入

修改后完整服务端代码

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace Servidor_Chat
{
    class Server
    {
        IPAddress ipAddr;
        IPEndPoint endPoint;
        Socket s_Server;
        // 客户端管理字典,key为客户端IP+端口,value为对应Socket
        Dictionary<string, Socket> clientSockets = new Dictionary<string, Socket>();
        // 锁对象,保证字典操作线程安全
        object lockObj = new object();

        public Server()
        {
            ipAddr = IPAddress.Any;
            endPoint = new IPEndPoint(ipAddr, 1234);
            s_Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            s_Server.Bind(endPoint);
            // 调整监听队列长度,支持多客户端接入
            s_Server.Listen(10);
        } 

        public void Start()
        {
            Console.WriteLine("等待客户端接入...");
            // 启动监听线程,循环处理客户端接入请求
            Thread acceptThread = new Thread(AcceptClientLoop);
            acceptThread.IsBackground = true;
            acceptThread.Start();
        }

        // 循环监听客户端接入
        private void AcceptClientLoop()
        {
            while (true)
            {
                Socket clientSocket = s_Server.Accept();
                IPEndPoint clientEP = (IPEndPoint)clientSocket.RemoteEndPoint;
                string clientKey = $"{clientEP.Address}:{clientEP.Port}";
                Console.WriteLine($"新客户端接入:{clientKey}");
                // 加入管理字典
                lock (lockObj)
                {
                    clientSockets.Add(clientKey, clientSocket);
                }
                // 为当前客户端启动接收线程
                Thread receiveThread = new Thread(ReceiveClientMsg);
                receiveThread.IsBackground = true;
                receiveThread.Start(clientSocket);
            }
        }

        // 接收指定客户端的消息
        private void ReceiveClientMsg(object obj)
        {
            Socket clientSocket = obj as Socket;
            string clientKey = $"{((IPEndPoint)clientSocket.RemoteEndPoint).Address}:{((IPEndPoint)clientSocket.RemoteEndPoint).Port}";
            while (true)
            {
                try
                {
                    byte[] ByRec = new byte[255];
                    int len = clientSocket.Receive(ByRec, 0, ByRec.Length, 0);
                    if (len == 0)
                    {
                        // 客户端正常断开
                        Console.WriteLine($"客户端{clientKey}断开连接");
                        lock (lockObj)
                        {
                            clientSockets.Remove(clientKey);
                        }
                        clientSocket.Close();
                        break;
                    }
                    string textoRecibido = Encoding.Default.GetString(ByRec, 0, len);
                    Console.WriteLine($"客户端[{clientKey}]: {textoRecibido}");
                    Console.Out.Flush();
                }
                catch (Exception ex)
                {
                    // 客户端异常断开
                    Console.WriteLine($"客户端{clientKey}异常断开:{ex.Message}");
                    lock (lockObj)
                    {
                        if (clientSockets.ContainsKey(clientKey))
                        {
                            clientSockets.Remove(clientKey);
                        }
                    }
                    clientSocket.Close();
                    break;
                }
            }
        }

        // 定向发送消息
        public void SendToTarget(string input)
        {
            // 输入格式:[目标客户端key] 消息内容,例如 127.0.0.1:54321 你好
            // 输入 all 消息内容 则广播给所有客户端
            var splitIndex = input.IndexOf(' ');
            if (splitIndex <= 0)
            {
                Console.WriteLine("输入格式错误,正确格式:[目标标识] 消息内容 或 all 消息内容");
                return;
            }
            string target = input.Substring(0, splitIndex);
            string msg = input.Substring(splitIndex + 1);
            byte[] msgBytes = Encoding.Default.GetBytes(msg);

            if (target == "all")
            {
                // 广播
                lock (lockObj)
                {
                    foreach (var socket in clientSockets.Values)
                    {
                        socket.Send(msgBytes, 0, msgBytes.Length, 0);
                    }
                }
                Console.WriteLine("广播消息发送完成");
                return;
            }

            // 定向发送
            lock (lockObj)
            {
                if (clientSockets.TryGetValue(target, out Socket targetSocket))
                {
                    targetSocket.Send(msgBytes, 0, msgBytes.Length, 0);
                    Console.WriteLine($"消息已发送给{target}");
                }
                else
                {
                    Console.WriteLine("目标客户端不存在");
                }
            }
        }
    } 

    class Program
    {
        static void Main(string[] args)
        {
            Server s = new Server();
            s.Start();
            while (true)
            {
                string input = Console.ReadLine();
                s.SendToTarget(input);
            } 

            Console.WriteLine("按任意键退出");
            Console.ReadLine();
        }
    }
}

客户端说明

原有客户端代码无需修改,直接运行即可,可多开多个客户端实例测试多连接效果。

测试步骤

  1. 启动服务端,控制台会打印等待客户端接入的提示
  2. 启动多个客户端,服务端会打印每个客户端的唯一标识(IP+端口)
  3. 服务端输入对应客户端标识加消息即可定向发送,例如输入127.0.0.1:54321 测试消息,对应客户端即可收到消息
  4. 输入all 全体通知即可给所有在线客户端发送广播消息

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 14:27:01