水煮养乐多 2023-02-17 09:45 采纳率: 100%
浏览 47
已结题

C# Socket 客户端 逻辑思路 【初学者提问】

初学者请教个问题,Winform程序作客户端连接多个服务端进行通讯,C# Socket 也是刚学,没找到合适的书或是资料,看了好多博客写了些,但是一直不能用,想请大伙给看看,提些问题或者建议,感谢的😁

public partial class Form1 : MaterialForm
    {
        #region 已知信息存有以下信息的DataTable表
        //dt表里存的是服务端的IP、端口号、还有发送的内容
        DataTable dt_ServerInfo = new DataTable();
        #endregion

        #region 变量声明
        private Dictionary<string, Socket> socketClients = new Dictionary<string, Socket>() { };    //客户端套接字集合
        byte[] dataSend = new byte[500];
        byte[] ReceiveByte = new byte[1024];
        #endregion

        #region 线程委托等实例
        Thread SendThr = null;
        #endregion

        public Form1()
        {
            InitializeComponent();
            GenerateDataTable();   //生成dt表结构和内容
            CreateSocketConnection();    //创建Socket和建立连接
        }

 #region 自定义函数
        private void CreateSocketConnection()
        {
            int countOfServers = dt_ServerInfo.Rows.Count;
            for (int i = 0; i < countOfServers; i++)
            {
                Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse(dt_ServerInfo.Rows[i]["serverIP"].ToString()),int.Parse(dt_ServerInfo.Rows[i]["serverPort"].ToString()));
                serverSocket.BeginConnect(serverEndPoint, new AsyncCallback(ConnectCallBack), serverSocket);
            }
        }

        private void ConnectCallBack(IAsyncResult asyncResult)
        {
            Socket client = (Socket)asyncResult.AsyncState; //客户端套接字
            try
            {
                client.EndConnect(asyncResult);
                socketClients.Add(client.RemoteEndPoint.ToString(), client);
            }
            catch (Exception)       //客户端开启后未连接,自动重连
            {
                IPEndPoint temppoint = (IPEndPoint)client.RemoteEndPoint;
                client.BeginConnect(temppoint, ConnectCallBack, client);
            }

        }

        private void SendThread()
        {
            while (socketClients.Count() > 0)
            {
                foreach (var item in socketClients)
                {
                    string serverInfo = item.Key.ToString();
                    //string tst = $"ServerIp = '{serverInfo.Split(':')[0]}' And ServerPort = '{serverInfo.Split(':')[1]}' ";
                    DataRow[] drs = dt_ServerInfo.Select($"ServerIp = '{serverInfo.Split(':')[0]}' And ServerPort = '{serverInfo.Split(':')[1]}'");
                    byte[] sendByte = hexStringToByteArray(drs[0]["Command"].ToString());
                    item.Value.BeginSend(sendByte, 0, sendByte.Length, SocketFlags.None, new AsyncCallback(SendCallback), item.Value);
                }
            }
        }

        private void SendCallback(IAsyncResult asyncResult)
        {
            Socket client = (Socket)asyncResult.AsyncState; //客户端套接字
            try
            {
                client.EndSend(asyncResult);
                client.BeginReceive(ReceiveByte, 0, ReceiveByte.Length, SocketFlags.None, new AsyncCallback(AsyncReceiveCall), client);
            }
            catch (Exception)       //当客户端无法发送命令时,自动断开连接并进行重连
            {
                IPEndPoint temppoint = (IPEndPoint)client.RemoteEndPoint;
                socketClients[temppoint.ToString()].Close();
                client.BeginConnect(temppoint, ConnectCallBack, client);
                socketClients.Remove(temppoint.ToString());
            }

        }

        private void AsyncReceiveCall(IAsyncResult asyncResult)
        {
            Socket client = (Socket)asyncResult.AsyncState; //客户端套接字
            int bytesRead = client.EndReceive(asyncResult);
            MessageBox.Show(ReceiveByte.ToString());
        }
  • 写回答

3条回答 默认 最新

  • Evaporator Core 2023-02-17 10:12
    关注

    这段代码中存在一些潜在的问题,可能会导致程序无法正常工作,以下是一些建议:

    1.Dictionary<string, Socket> 可能会导致线程不安全的问题。由于你的应用程序需要在多个线程中操作套接字,因此如果在操作中修改集合,可能会导致线程竞争条件。因此,建议使用 ConcurrentDictionary<string, Socket> 代替 Dictionary<string, Socket> 来确保线程安全。
    2.ConnectCallBack() 方法中的异常处理可以更加细致。当前的处理是在发生任何异常时进行自动重连,但这可能会导致无限次的重连尝试。建议对特定的异常类型进行处理,并在重试次数达到一定限制后停止重连。
    3.SendThread() 中的 foreach 循环可能会导致性能问题。在此方法中,每个循环迭代都会向套接字发送命令,并在返回时等待异步回调,这可能会导致很多线程被阻塞。可以考虑将发送命令的过程与异步回调分开,并将异步回调委托给另一个线程处理。
    4.AsyncReceiveCall() 方法中 MessageBox.Show(ReceiveByte.ToString()) 可能不会正确显示接收到的数据。当前的代码将字节数组转换为字符串并将其显示在消息框中。但这种转换方法可能会导致不可预测的结果,因为字节数组中的每个字节都不一定是有效的 ASCII 字符。建议使用 System.Text.Encoding 类来将字节数组转换为字符串,例如 Encoding.UTF8.GetString(ReceiveByte, 0, bytesRead)。
    希望这些建议可以帮助你改进你的程序并解决你遇到的问题。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

问题事件

  • 系统已结题 2月25日
  • 已采纳回答 2月17日
  • 创建了问题 2月17日

悬赏问题

  • ¥25 大学xml问答,会的请回复
  • ¥15 小贝360-4 配二个 华772S 设置WⅰFi5G 连接
  • ¥15 vs2022的QT报错,好像是缺少winextras
  • ¥15 怎么看 cst中一个面的功率分布图
  • ¥15 c语言数据结构求9999
  • ¥15 Fiddler无法对部分小程序抓包
  • ¥60 Python代码 ip首部检验和计算代码 版本协议 首部长度 源地址 目的地址 存活时间
  • ¥18 微机原理汇编的综合实验
  • ¥15 LD衰减图用R语言对其可视化
  • ¥15 Mermaid语法生成的svg在Axure无法编辑