C# - Socket 基础指南

C# Socket 编程完全指南

第 1 章:Socket 编程基础

1.1 什么是 Socket

Socket(套接字)是网络通信的端点,提供了应用程序与网络协议之间的接口。在C#中,System.Net.Sockets命名空间提供了完整的Socket编程支持。

通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据;

套接字就是四元组,即源ip+端口port 目的ip+端口port,表示绝对唯一的连接;

Socket 是在应用层(Http、SSH、FTP)和传输层(TCP、UDP)之间的一个抽象层,它把 TCP/IP 层复杂的操作抽象为几个简单的接口,供应用层调用实现进程在网络中的通信;

实际上socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议;

1.2 Socket 通信模型

  • TCP Socket:面向连接的可靠通信
  • UDP Socket:无连接的快速通信
  • 原始 Socket:直接访问网络层协议

1.3 核心命名空间

using System.Net;
using System.Net.Sockets;
using System.Text;

1.4 流程

服务器端:
第一步:建立一个用于通信的Socket对象
第二步:使用bind绑定IP地址和端口号
第三步:使用listen监听客户端
第四步:使用accept中断程序直到连接上客户端
第五步:接收来自客户端的请求
第六步:返回客户端需要的数据
第七步:如果接收到客户端已关闭连接信息就关闭服务器端

客户端:
第一步:建立一个用于通信的Socket对象
第二步:根据指定的IP和端口connet服务器
第三步:连接成功后向服务器端发送数据请求
第四步:接收服务器返回的请求数据
第五步:如果还需要请求数据继续发送请求
Socket

image

[例子] 服务端例子A:(Socket 版本)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SocketDemo1
{
    public partial class Form1 : Form
    {
        Socket socketWatch = null;
        List<Socket> connectedClients = new List<Socket>();
        public Form1()
        {
            InitializeComponent();
        }

        //初始化Socket
        private void InitService()
        {
            try
            {
                //第一步.创建监听套接字 使用 ip4协议,流式传输,TCP连接
                socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //绑定端口
                //第2.1步 获取网络节点对象
                IPAddress address = IPAddress.Any;// IPAddress.Parse(this.txt_IP.Text);
                IPEndPoint endPoint = new IPEndPoint(address, int.Parse(txt_Port.Text));
                //第2.2步 绑定端口(其实内部就像系统端口表中注册了一个端口,并指定了当前句柄)
                socketWatch.Bind(endPoint);
                //第三步 设置监听队列
                socketWatch.Listen(10);
                ShowMsg($"服务器[{socketWatch.LocalEndPoint}]:启动成功!");
            }
            catch (Exception ex)
            {
                ShowMsg($"启动失败:{ex.Message}");
            }
        }

        //开始监听
        private async void btn_startListen_Click(object sender, EventArgs e)
        {
            try
            {
                this.btn_startListen.Text = "监听中";
                // 如果监听器已经启动,先停止它
                if (socketWatch != null)
                {
                    socketWatch.Close();
                    socketWatch = null;
                    this.btn_startListen.Text = "开始监听";
                    ShowMsg($"服务器:已关闭!");
                    return;
                }

                InitService();

                _ = Task.Run(async () =>
                {
                    ShowMsg("监听开始");

                    while (true)
                    {
                        //第四步.开始监听 此方法会阻断当前线程,直到有其他程序连接
                        Socket clientSocket = await socketWatch.AcceptAsync();
                        ShowMsg($"[客户端:{clientSocket.RemoteEndPoint}]连接!");

                        // 将客户端添加到连接列表
                        lock (connectedClients)
                        {
                            connectedClients.Add(clientSocket);
                        }

                        _ = Task.Run(async () =>
                        {
                            await ReceiveMsg(clientSocket);
                        });
                    }
                });
            }
            catch (Exception ex)
            {

                ShowMsg($"监听错误:{ex.Message}");
            }


        }


        async Task ReceiveMsg(Socket clientSocket)
        {
            while (true)
            {
                byte[] buffer = new byte[1024 * 4]; //4kb 普通文本够用了

                //var count = clientSocket.Receive(buffer);
                ArraySegment<byte> bufferSegment = new ArraySegment<byte>(buffer);
                //第五步 接收
                int count = await clientSocket.ReceiveAsync(bufferSegment, SocketFlags.None);

                #region 判断客户端连接是否关闭
                if (count == 0) //判断客户端连接是否关闭
                {
                    ShowMsg($"[客户端:{clientSocket.RemoteEndPoint}]:关闭连接!");
                    // 从连接列表中移除客户端
                    lock (connectedClients)
                    {
                        connectedClients.Remove(clientSocket);
                    }
                    clientSocket.Close();
                    break;
                }
                #endregion

                string str = Encoding.UTF8.GetString(buffer, 0, count);

                ShowMsg($"[客户端:{clientSocket.RemoteEndPoint}]:{str}");
            }

        }


        //显示监听消息方法
        void ShowMsg(string strmsg)
        {
            string dateNow = DateTime.Now.ToString("yyyy-mm-dd HH:mm:ss");

            if (this.rtb_receive.InvokeRequired)
            {
                this.Invoke(new Action(() =>
                {
                    this.rtb_receive.AppendText($"[{dateNow}]{strmsg} \r\n");
                    this.rtb_receive.SelectionStart = this.rtb_receive.Text.Length;
                    this.rtb_receive.ScrollToCaret();
                }));
            }
            else
            {
                this.rtb_receive.AppendText($"[{dateNow}]{strmsg} \r\n");
                this.rtb_receive.SelectionStart = this.rtb_receive.Text.Length;
                this.rtb_receive.ScrollToCaret();
            }

        }

        // 发送消息给所有客户端
        private async void btn_send_Click(object sender, EventArgs e)
        {
            try
            {
                string message = rtb_send.Text?.Trim();
                if (string.IsNullOrEmpty(message))
                {
                    ShowMsg("发送消息不能为空!");
                    return;
                }

                // 获取当前连接的客户端列表
                Socket[] clients;
                lock (connectedClients)
                {
                    clients = connectedClients.ToArray();
                }

                if (clients.Length == 0)
                {
                    ShowMsg("没有连接的客户端!");
                    return;
                }

                byte[] data = Encoding.UTF8.GetBytes(message);
                int successCount = 0;

                foreach (var client in clients)
                {
                    try
                    {
                        if (client.Connected)
                        {
                            await client.SendAsync(new ArraySegment<byte>(data), SocketFlags.None);
                            successCount++;
                        }
                    }
                    catch (Exception ex)
                    {
                        ShowMsg($"发送消息到客户端失败:{ex.Message}");
                        // 从连接列表中移除失效的客户端
                        lock (connectedClients)
                        {
                            connectedClients.Remove(client);
                        }
                    }
                }

                ShowMsg($"消息发送成功:{message} (发送给 {successCount}/{clients.Length} 个客户端)");
                rtb_send.Text = ""; // 清空发送框
            }
            catch (Exception ex)
            {
                ShowMsg($"发送消息错误:{ex.Message}");
            }
        }

        // 窗体关闭时清理资源
        protected override void OnFormClosed(FormClosedEventArgs e)
        {
            // 关闭监听Socket
            socketWatch?.Close();

            // 关闭所有客户端连接
            lock (connectedClients)
            {
                foreach (var client in connectedClients)
                {
                    client?.Close();
                }
                connectedClients.Clear();
            }

            base.OnFormClosed(e);
        }
    }
}

[例子] 客户端例子A:(Socket 版本)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SocketClientDemo1
{
    public partial class Form1 : Form
    {
        private Socket clientSocket;
        private bool isConnected = false;

        public Form1()
        {
            InitializeComponent();
        }

        private async void InitClient()
        {
            await ConnectAsync("127.0.0.1", 60000);
        }

        public async Task ConnectAsync(string server, int port)
        {
            if (clientSocket != null)
            {
                try
                {
                    // 检查socket是否已被释放
                    var test = clientSocket.Connected;
                }
                catch (ObjectDisposedException)
                {
                    clientSocket = null;
                }
            }

            if (clientSocket == null)
            {
                clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            }

            try
            {
                if (!clientSocket.Connected)
                {
                    // 使用异步连接
                    await Task.Run(() =>
                    {
                        clientSocket.Connect(new IPEndPoint(IPAddress.Parse(server), port));
                    });

                    ShowMsg("已连接到服务器");

                    // 启动接收线程
                    _ = Task.Run(ReceiveDataAsync);

                    isConnected = true;
                    this.btn_open.Enabled = false;
                    this.btn_close.Enabled = true;
                }
            }
            catch (SocketException ex)
            {
                ShowMsg($"连接错误: {ex.Message}");
                //clientSocket = null;
                isConnected = false;
                Disconnect();

            }
            catch (ObjectDisposedException)
            {
                ShowMsg("连接错误: Socket对象已被释放,请重试");
                //clientSocket = null;
                isConnected = false;

            }
            catch (Exception ex)
            {
                ShowMsg($"连接错误: {ex.Message}");
                //clientSocket = null;
                isConnected = false;
            }
        }


        private async Task ReceiveDataAsync()
        {
            byte[] buffer = new byte[1024];

            try
            {
                while (clientSocket != null && clientSocket.Connected && isConnected)
                {
                    if (clientSocket.Available > 0)
                    {
                        int bytesRead = await Task.Run(() => clientSocket.Receive(buffer));
                        if (bytesRead == 0) break;

                        string receivedMessage = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                        ShowMsg($"服务器回复: {receivedMessage}");
                    }
                }
            }
            catch (SocketException ex)
            {
                ShowMsg($"接收错误: {ex.Message}");
            }
            catch (ObjectDisposedException)
            {
                ShowMsg("连接已断开");
            }
            catch (Exception ex)
            {
                ShowMsg($"接收错误: {ex.Message}");
            }
            //finally
            //{
            //    Disconnect();
            //}
        }


        private async void btn_send_Click(object sender, EventArgs e)
        {
            if (clientSocket == null || !clientSocket.Connected || !isConnected)
            {
                MessageBox.Show("请先连接到服务器");
                return;
            }

            if (string.IsNullOrWhiteSpace(rtb_send.Text))
            {
                MessageBox.Show("请输入要发送的消息");
                return;
            }

            try
            {
                string message = rtb_send.Text;
                byte[] data = Encoding.UTF8.GetBytes(message);

                // 使用Socket的异步发送方法
                int bytesSent = await Task.Run(() => clientSocket.Send(data));

                if (bytesSent > 0)
                {
                    rtb_send.Clear();
                    ShowMsg($"已发送: {message}");
                }
            }
            catch (SocketException ex)
            {
                MessageBox.Show($"发送错误: {ex.Message}");
            }
            catch (ObjectDisposedException)
            {
                MessageBox.Show("连接已断开,请重新连接");
                isConnected = false;
            }
            catch (Exception ex)
            {
                MessageBox.Show($"发送错误: {ex.Message}");
            }
        }

        void ShowMsg(string strmsg)
        {
            string dateNow = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

            if (this.rtb_receive.InvokeRequired)
            {
                this.Invoke(new Action(() =>
                {
                    this.rtb_receive.AppendText($"[{dateNow}]{strmsg} \r\n");
                    this.rtb_receive.SelectionStart = this.rtb_receive.Text.Length;
                    this.rtb_receive.ScrollToCaret();
                }));
            }
            else
            {
                this.rtb_receive.AppendText($"[{dateNow}]{strmsg} \r\n");
                this.rtb_receive.SelectionStart = this.rtb_receive.Text.Length;
                this.rtb_receive.ScrollToCaret();
            }

        }

        #region 连接/断开
        private void btn_open_Click(object sender, EventArgs e)
        {
            InitClient();
        }

        private void btn_close_Click(object sender, EventArgs e)
        {
            Disconnect();
        }
        #endregion

        public void Disconnect()
        {
            try
            {
                if (clientSocket != null)
                {
                    if (clientSocket.Connected)
                    {
                        clientSocket.Shutdown(SocketShutdown.Both);
                    }
                    clientSocket.Close();
                    clientSocket.Dispose();

                }

                isConnected = false;
                this.btn_open.Enabled = true;
                this.btn_close.Enabled = false;
            }
            catch (Exception ex)
            {
                ShowMsg($"断开连接错误: {ex.Message}");
            }
            finally
            {
                clientSocket = null;
                isConnected = false;
                ShowMsg("已断开连接");
            }
        }
    }
}

1.5 TcpListener 服务器端步骤:

TcpListener 是.NET 中专门用于 TCP 服务器端的高级封装类,它简化了基于 TCP 协议的服务器端 Socket 编程流程,底层同样依赖 Socket,但隐藏了许多底层细节。对比你列出的 Socket 服务器端步骤,TcpListener 的工作流程如下:

  1. 创建 TcpListener 对象

    直接指定要监听的 IP 地址和端口号(无需手动创建底层 Socket),例如:

    TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 8888);
    

    (内部已封装 Socket 的创建,默认使用 TCP 协议的 Socket)

  2. 启动监听(Start)

    调用 Start() 方法启动服务器,替代了 Socket 的 Bind()Listen() 两步操作:

    server.Start(); // 内部自动完成绑定IP+端口、设置监听队列等
    
  3. 等待客户端连接(AcceptTcpClient)

    调用 AcceptTcpClient() 方法(阻塞当前线程),直到有客户端连接,返回一个 TcpClient 对象(封装了与客户端的连接),替代 Socket 的 Accept()

    TcpClient client = server.AcceptTcpClient(); // 类似Socket的Accept(),但返回TcpClient
    
  4. 获取通信流(NetworkStream)

    通过 TcpClient.GetStream() 获取网络流,用于收发数据,替代 Socket 的 Receive()Send()

    NetworkStream stream = client.GetStream();
    
  5. 接收客户端请求

    使用 stream.Read() 从流中读取客户端发送的数据:

    byte[] buffer = new byte[1024];
    int bytesRead = stream.Read(buffer, 0, buffer.Length);
    string request = Encoding.UTF8.GetString(buffer, 0, bytesRead);
    
  6. 向客户端返回数据

    使用 stream.Write() 向流中写入响应数据:

    byte[] response = Encoding.UTF8.GetBytes("已收到请求");
    stream.Write(response, 0, response.Length);
    
  7. 关闭连接与服务器

    当客户端断开连接(如流读取到 0 字节),关闭 TcpClient 和流,最终停止服务器:

    stream.Close();
    client.Close();
    server.Stop(); // 停止监听并释放资源
    

[例子] 服务端例子A:(TcpListener 版本)

image

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SocketDemo1
{
    public partial class Form1 : Form
    {
        TcpListener tcpListener = null;
        List<TcpClient> connectedClients = new List<TcpClient>();
        private bool isRunning = false;
        public Form1()
        {
            InitializeComponent();
        }

        private void InitService()
        {
            try
            {
                // 使用 TcpListener 替代 Socket
                int port = int.Parse(txt_Port.Text);
                tcpListener = new TcpListener(IPAddress.Any, port);
                tcpListener.Start();
                ShowMsg($"服务器[{tcpListener.LocalEndpoint}]:启动成功!");
            }
            catch (Exception ex)
            {
                ShowMsg($"启动失败:{ex.Message}");
            }
        }

        //启动监听
        private async void btn_startListen_Click(object sender, EventArgs e)
        {
            try
            {
                this.btn_startListen.Text = "监听中"; 
                isRunning = true;
                // 如果监听器已经启动,先停止它
                if (tcpListener != null)
                {
                    tcpListener.Stop();
                    tcpListener = null;
                    this.btn_startListen.Text = "开始监听";
                    ShowMsg($"服务器:已关闭!");
                    return;
                }
                
                // 初始化服务
                InitService();
                
                // 启动后台任务持续监听客户端连接
                _ = Task.Run(async () =>
                {
                    ShowMsg("监听开始,等待客户端连接...");

                    while (isRunning)
                    {
                        try
                        {
                            // 使用 AcceptTcpClientAsync 替代 Socket.AcceptAsync
                            TcpClient tcpClient = await tcpListener.AcceptTcpClientAsync();
                            ShowMsg($"[客户端:{tcpClient.Client.RemoteEndPoint}]连接!");

                            // 将客户端添加到连接列表
                            lock (connectedClients)
                            {
                                connectedClients.Add(tcpClient);
                            }

                            // 为每个客户端启动独立的任务处理消息
                            _ = Task.Run(async () =>
                            {
                                await ReceiveMsg(tcpClient);
                            });
                        }
                        catch (ObjectDisposedException)
                        {
                            // 监听器被正常关闭,退出循环
                            isRunning = false;
                            break;
                        }
                        catch (Exception ex)
                        {
                            ShowMsg($"接受客户端连接错误:{ex.Message}");
                            isRunning = false;
                        }
                    }
                });
            }
            catch (Exception ex)
            {
                ShowMsg($"监听错误:{ex.Message}");
                this.btn_startListen.Text = "开始监听";
                isRunning = false;
            }
        }


        async Task ReceiveMsg(TcpClient tcpClient)
        {
            try
            {
                NetworkStream stream = tcpClient.GetStream();
                byte[] buffer = new byte[1024 * 4]; // 4KB 缓冲区

                while (isRunning)
                {
                    // 使用 NetworkStream.ReadAsync 接收数据
                    int count = await stream.ReadAsync(buffer, 0, buffer.Length);
                    
                    // 判断连接是否关闭
                    if (count == 0)
                    {
                        ShowMsg($"[客户端:{tcpClient.Client.RemoteEndPoint}]:关闭连接!");
                        // 从连接列表中移除客户端
                        lock (connectedClients)
                        {
                            connectedClients.Remove(tcpClient);
                        }
                        tcpClient.Close();
                        break;
                    }

                    // 处理接收到的数据
                    string str = Encoding.UTF8.GetString(buffer, 0, count);
                    ShowMsg($"[客户端:{tcpClient.Client.RemoteEndPoint}]:{str}");
                }
            }
            catch (Exception ex)
            {
                ShowMsg($"与客户端[{tcpClient.Client.RemoteEndPoint}]通信错误:{ex.Message}");
                // 从连接列表中移除客户端
                lock (connectedClients)
                {
                    connectedClients.Remove(tcpClient);
                }
                tcpClient.Close();
                this.btn_startListen.Text = "开始监听";
                isRunning = false;
            }
        }

        //显示监听消息方法
        void ShowMsg(string strmsg)
        {
            string dateNow = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

            if (this.rtb_receive.InvokeRequired)
            {
                this.Invoke(new Action(() =>
                {
                    this.rtb_receive.AppendText($"[{dateNow}]{strmsg} \r\n");
                    this.rtb_receive.SelectionStart = this.rtb_receive.Text.Length;
                    this.rtb_receive.ScrollToCaret();
                }));
            }
            else
            {
                this.rtb_receive.AppendText($"[{dateNow}]{strmsg} \r\n");
                this.rtb_receive.SelectionStart = this.rtb_receive.Text.Length;
                this.rtb_receive.ScrollToCaret();
            }

        }

        // 发送消息给所有客户端
        private async void btn_send_Click(object sender, EventArgs e)
        {
            try
            {
                string message = rtb_send.Text?.Trim();
                if (string.IsNullOrEmpty(message))
                {
                    ShowMsg("发送消息不能为空!");
                    return;
                }

                // 获取当前连接的客户端列表
                TcpClient[] clients;
                lock (connectedClients)
                {
                    clients = connectedClients.ToArray();
                }

                if (clients.Length == 0)
                {
                    ShowMsg("没有连接的客户端!");
                    return;
                }

                byte[] data = Encoding.UTF8.GetBytes(message);
                int successCount = 0;

                foreach (var client in clients)
                {
                    try
                    {
                        if (client.Connected)
                        {
                            NetworkStream stream = client.GetStream();
                            await stream.WriteAsync(data, 0, data.Length);
                            successCount++;
                        }
                    }
                    catch (Exception ex)
                    {
                        ShowMsg($"发送消息到客户端失败:{ex.Message}");
                        // 从连接列表中移除失效的客户端
                        lock (connectedClients)
                        {
                            connectedClients.Remove(client);
                        }
                    }
                }

                ShowMsg($"消息发送成功:{message} (发送给 {successCount}/{clients.Length} 个客户端)");
                rtb_send.Text = ""; // 清空发送框
            }
            catch (Exception ex)
            {
                ShowMsg($"发送消息错误:{ex.Message}");
            }
        }

        // 窗体关闭时清理资源
        protected override void OnFormClosed(FormClosedEventArgs e)
        {
            tcpListener?.Stop();
            
            // 关闭所有客户端连接
            lock (connectedClients)
            {
                foreach (var client in connectedClients)
                {
                    client?.Close();
                }
                connectedClients.Clear();
            }
            
            base.OnFormClosed(e);
        }
    }
}

1.6 TcpClient 客户端步骤:

  1. 创建 TcpClient 对象

    初始化客户端对象(可无参创建,后续连接时指定地址和端口;也可在构造函数中直接指定)。

    TcpClient client = new TcpClient(); // 无参构造,后续调用Connect连接
    // 或直接在构造函数中指定服务器地址和端口(内部自动连接)
    // TcpClient client = new TcpClient("127.0.0.1", 8888);
    
  2. 连接服务器(Connect)

    调用 Connect 方法,指定服务器的 IP 地址(或主机名)和端口号,建立 TCP 连接。

    string serverIp = "127.0.0.1"; // 服务器IP
    int port = 8888; // 服务器监听的端口
    client.Connect(serverIp, port); // 阻塞直到连接成功或失败(失败会抛异常)
    
  3. 获取网络流(NetworkStream)

    通过 GetStream() 方法获取与服务器通信的网络流(NetworkStream),后续通过流进行数据的读写。

    NetworkStream stream = client.GetStream();
    
  4. 向服务器发送数据

    将需要发送的数据(字符串或字节数组)通过 stream.Write() 写入流,发送给服务器。

    string message = "Hello, Server!";
    byte[] data = Encoding.UTF8.GetBytes(message); // 转换为字节数组
    stream.Write(data, 0, data.Length); // 发送数据
    
  5. 接收服务器的响应

    使用 stream.Read() 从流中读取服务器返回的数据(需提前定义缓冲区)。

    byte[] buffer = new byte[1024]; // 缓冲区,用于存放接收的数据
    int bytesRead = stream.Read(buffer, 0, buffer.Length); // 读取数据(返回实际读取的字节数)
    string response = Encoding.UTF8.GetString(buffer, 0, bytesRead); // 转换为字符串
    Console.WriteLine("收到服务器响应:" + response);
    
  6. 关闭连接与释放资源

    通信完成后,依次关闭流和 TcpClient,释放资源(建议使用 using 语句自动释放)。

    stream.Close(); // 关闭流
    client.Close(); // 关闭客户端连接
    

[例子] 客户端例子B:(TcpClient 版本)

image

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SocketClientDemo1
{
    public partial class Form1 : Form
    {
        private TcpClient client;
        private NetworkStream stream;
        public Form1()
        {
            InitializeComponent();
        }

        private async void InitClient()
        {
            await ConnectAsync("127.0.0.1", 60000);
        }

        public async Task ConnectAsync(string server, int port)
        {

            if (client == null)
            {
                client = new TcpClient();
            }

            try
            {
                if (!client.Connected)
                {
                    await client.ConnectAsync(server, port);
                    stream = client.GetStream();
                    ShowMsg("已连接到服务器");

                    // 启动接收线程
                    _ = Task.Run(ReceiveDataAsync);
                }
            }
            catch(SocketException ex)
            {
                //连接错误: 由于目标计算机积极拒绝,无法连接。 127.0.0.1:60000 
                ShowMsg($"连接错误: {ex.Message}");
                client = null; // 重置client以便下次重新创建
            }
            catch (ObjectDisposedException)
            {
                ShowMsg("连接错误: 连接对象已被释放,请重试");
                client = null; // 重置client以便下次重新创建
            }
            catch (NullReferenceException)
            {
                ShowMsg("连接错误: 未将对象引用设置到对象的实例,请重试");
                client = null; // 重置client以便下次重新创建
            }
            catch (Exception ex)
            {
                Console.WriteLine($"连接错误: {ex.Message}");
                ShowMsg($"连接错误: {ex.Message}");
            }
        }


        private async Task ReceiveDataAsync()
        {
            byte[] buffer = new byte[1024];

            try
            {
                while (client != null && client.Connected && stream != null)
                {
                    int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
                    if (bytesRead == 0) break;

                    string receivedMessage = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                    Console.WriteLine($"服务器回复: {receivedMessage}");
                    ShowMsg(receivedMessage);
                }
            }
            catch (ObjectDisposedException)
            {
                // 流已被释放,正常断开连接
                ShowMsg("连接已断开");
                client = null;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"接收错误: {ex.Message}");
                ShowMsg($"接收错误: {ex.Message}");
            }
        }


        private async void btn_send_Click(object sender, EventArgs e)
        {
            if (client == null || !client.Connected || stream == null)
            {
                MessageBox.Show("请先连接到服务器");
                return;
            }

            if (string.IsNullOrWhiteSpace(rtb_send.Text))
            {
                MessageBox.Show("请输入要发送的消息");
                return;
            }

            try
            {
                string message = rtb_send.Text;
                byte[] data = Encoding.UTF8.GetBytes(message);
                await stream.WriteAsync(data, 0, data.Length);
                rtb_send.Clear();
            }
            catch (ObjectDisposedException)
            {
                MessageBox.Show("连接已断开,请重新连接");
            }
            catch (Exception ex)
            {
                MessageBox.Show($"发送错误: {ex.Message}");
            }
        }

        void ShowMsg(string strmsg)
        {
            string dateNow = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

            if (this.rtb_receive.InvokeRequired)
            {
                this.Invoke(new Action(() =>
                {
                    this.rtb_receive.AppendText($"[{dateNow}]{strmsg} \r\n");
                    this.rtb_receive.SelectionStart = this.rtb_receive.Text.Length;
                    this.rtb_receive.ScrollToCaret();
                }));
            }
            else
            {
                this.rtb_receive.AppendText($"[{dateNow}]{strmsg} \r\n");
                this.rtb_receive.SelectionStart = this.rtb_receive.Text.Length;
                this.rtb_receive.ScrollToCaret();
            }

        }

        #region 连接/断开
        private void btn_open_Click(object sender, EventArgs e)
        {
            InitClient();
            this.btn_open.Enabled = false;
            this.btn_close.Enabled = true;
        }

        private void btn_close_Click(object sender, EventArgs e)
        {
            Disconnect();
            this.btn_open.Enabled = true;
            this.btn_close.Enabled = false;
        }
        #endregion
            
        public void Disconnect()
        {
            stream?.Close();
            client?.Close();
            ShowMsg("已断开连接");
        }
    }
}

第 2 章:TCP Socket 编程

2.1 TCP 服务器端实现

2.1.1 基础TCP服务器

public class TcpServer
{
    private TcpListener listener;
    private bool isRunning;

    public TcpServer(string ipAddress, int port)
    {
        IPAddress localAddr = IPAddress.Parse(ipAddress);
        listener = new TcpListener(localAddr, port);
    }

    public void Start()
    {
        isRunning = true;
        listener.Start();
        Console.WriteLine("TCP服务器已启动,等待客户端连接...");

        while (isRunning)
        {
            try
            {
                // 接受客户端连接(阻塞方法)
                TcpClient client = listener.AcceptTcpClient();
                Console.WriteLine($"客户端已连接: {client.Client.RemoteEndPoint}");

                // 为每个客户端创建独立线程处理
                Thread clientThread = new Thread(HandleClient);
                clientThread.Start(client);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"接受连接错误: {ex.Message}");
            }
        }
    }

    private void HandleClient(object obj)
    {
        TcpClient client = (TcpClient)obj;
        NetworkStream stream = client.GetStream();
        byte[] buffer = new byte[1024];
        int bytesRead;

        try
        {
            while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
            {
                string receivedData = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                Console.WriteLine($"收到数据: {receivedData}");

                // 回显数据给客户端
                byte[] response = Encoding.UTF8.GetBytes($"服务器回复: {receivedData}");
                stream.Write(response, 0, response.Length);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"处理客户端错误: {ex.Message}");
        }
        finally
        {
            client.Close();
            Console.WriteLine("客户端已断开连接");
        }
    }

    public void Stop()
    {
        isRunning = false;
        listener.Stop();
    }
}

// 使用示例
TcpServer server = new TcpServer("127.0.0.1", 8080);
server.Start();

2.1.2 异步TCP服务器

public class AsyncTcpServer
{
    private TcpListener listener;
    private CancellationTokenSource cancellationTokenSource;

    public AsyncTcpServer(string ipAddress, int port)
    {
        IPAddress localAddr = IPAddress.Parse(ipAddress);
        listener = new TcpListener(localAddr, port);
        cancellationTokenSource = new CancellationTokenSource();
    }

    public async Task StartAsync()
    {
        listener.Start();
        Console.WriteLine("异步TCP服务器已启动");

        try
        {
            while (!cancellationTokenSource.Token.IsCancellationRequested)
            {
                TcpClient client = await listener.AcceptTcpClientAsync();
                _ = HandleClientAsync(client, cancellationTokenSource.Token);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"服务器错误: {ex.Message}");
        }
    }

    private async Task HandleClientAsync(TcpClient client, CancellationToken token)
    {
        using (client)
        using (NetworkStream stream = client.GetStream())
        {
            byte[] buffer = new byte[1024];

            try
            {
                while (!token.IsCancellationRequested)
                {
                    int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, token);
                    if (bytesRead == 0) break;

                    string receivedData = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                    Console.WriteLine($"收到数据: {receivedData}");

                    // 异步发送回复
                    byte[] response = Encoding.UTF8.GetBytes($"异步回复: {receivedData}");
                    await stream.WriteAsync(response, 0, response.Length, token);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"客户端处理错误: {ex.Message}");
            }
        }

        Console.WriteLine("客户端连接已关闭");
    }

    public void Stop()
    {
        cancellationTokenSource.Cancel();
        listener.Stop();
    }
}

2.2 TCP 客户端实现

2.2.1 基础TCP客户端

public class TcpClientExample
{
    private TcpClient client;
    private NetworkStream stream;

    public async Task ConnectAsync(string server, int port)
    {
        client = new TcpClient();

        try
        {
            await client.ConnectAsync(server, port);
            stream = client.GetStream();
            Console.WriteLine("已连接到服务器");

            // 启动接收线程
            _ = Task.Run(ReceiveDataAsync);

            // 启动发送循环
            await SendDataLoopAsync();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"连接错误: {ex.Message}");
        }
    }

    private async Task SendDataLoopAsync()
    {
        try
        {
            while (client.Connected)
            {
                Console.Write("请输入要发送的消息: ");
                string message = Console.ReadLine();

                if (message?.ToLower() == "exit") break;

                byte[] data = Encoding.UTF8.GetBytes(message);
                await stream.WriteAsync(data, 0, data.Length);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"发送错误: {ex.Message}");
        }
    }

    private async Task ReceiveDataAsync()
    {
        byte[] buffer = new byte[1024];

        try
        {
            while (client.Connected)
            {
                int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
                if (bytesRead == 0) break;

                string receivedMessage = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                Console.WriteLine($"服务器回复: {receivedMessage}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"接收错误: {ex.Message}");
        }
        finally
        {
            Disconnect();
        }
    }

    public void Disconnect()
    {
        stream?.Close();
        client?.Close();
        Console.WriteLine("已断开连接");
    }
}

// 使用示例
TcpClientExample client = new TcpClientExample();
await client.ConnectAsync("127.0.0.1", 8080);

第 3 章:UDP Socket 编程

3.1 UDP 服务器实现

public class UdpServer
{
    private UdpClient udpClient;
    private IPEndPoint remoteEndPoint;
    private bool isRunning;

    public UdpServer(int port)
    {
        udpClient = new UdpClient(port);
        remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
    }

    public async Task StartAsync()
    {
        isRunning = true;
        Console.WriteLine("UDP服务器已启动");

        try
        {
            while (isRunning)
            {
                // 接收数据
                UdpReceiveResult result = await udpClient.ReceiveAsync();
                string receivedData = Encoding.UTF8.GetString(result.Buffer);
                Console.WriteLine($"收到来自 {result.RemoteEndPoint} 的数据: {receivedData}");

                // 发送回复
                string response = $"UDP服务器回复: {receivedData}";
                byte[] responseData = Encoding.UTF8.GetBytes(response);
                await udpClient.SendAsync(responseData, responseData.Length, result.RemoteEndPoint);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"UDP服务器错误: {ex.Message}");
        }
    }

    public void Stop()
    {
        isRunning = false;
        udpClient.Close();
    }
}

3.2 UDP 客户端实现

public class UdpClientExample
{
    private UdpClient udpClient;
    private IPEndPoint serverEndPoint;

    public UdpClientExample(string server, int port)
    {
        udpClient = new UdpClient();
        serverEndPoint = new IPEndPoint(IPAddress.Parse(server), port);
    }

    public async Task SendMessageAsync(string message)
    {
        try
        {
            byte[] data = Encoding.UTF8.GetBytes(message);
            await udpClient.SendAsync(data, data.Length, serverEndPoint);

            // 接收回复
            UdpReceiveResult result = await udpClient.ReceiveAsync();
            string response = Encoding.UTF8.GetString(result.Buffer);
            Console.WriteLine($"服务器回复: {response}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"UDP发送错误: {ex.Message}");
        }
    }

    public void Close()
    {
        udpClient.Close();
    }
}

// 使用示例
UdpClientExample udpClient = new UdpClientExample("127.0.0.1", 8081);
await udpClient.SendMessageAsync("Hello UDP Server");

第 4 章:Socket 高级特性

4.1 Socket 选项配置

public class AdvancedSocketConfig
{
    public void ConfigureSocket(Socket socket)
    {
        // 设置发送缓冲区大小
        socket.SendBufferSize = 8192;

        // 设置接收缓冲区大小
        socket.ReceiveBufferSize = 8192;

        // 设置发送超时(毫秒)
        socket.SendTimeout = 5000;

        // 设置接收超时(毫秒)
        socket.ReceiveTimeout = 5000;

        // 启用地址重用
        socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

        // 设置KeepAlive
        socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);

        // 禁用Nagle算法(减少延迟)
        socket.NoDelay = true;

        // 设置Linger选项
        LingerOption lingerOption = new LingerOption(true, 10); // 延迟10秒关闭
        socket.LingerState = lingerOption;
    }
}

4.2 多路复用 I/O(Select模式)

public class SocketMultiplexer
{
    private List<Socket> socketList = new List<Socket>();

    public void AddSocket(Socket socket)
    {
        socketList.Add(socket);
    }

    public void StartMonitoring()
    {
        while (true)
        {
            // 检查可读的Socket
            Socket.Select(socketList, null, null, 1000000); // 1秒超时

            foreach (Socket socket in socketList)
            {
                if (socket.Available > 0)
                {
                    // 处理接收数据
                    byte[] buffer = new byte[1024];
                    int bytesRead = socket.Receive(buffer);
                    string data = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                    Console.WriteLine($"收到数据: {data}");
                }
            }
        }
    }
}

第 5 章:协议设计与数据序列化

5.1 自定义协议设计

// 协议头定义
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct MessageHeader
{
    public int MessageId;      // 消息ID
    public int BodyLength;    // 消息体长度
    public MessageType Type;   // 消息类型
}

public enum MessageType
{
    Text = 1,
    Binary = 2,
    Command = 3
}

// 消息序列化器
public class MessageSerializer
{
    public static byte[] SerializeMessage(int messageId, MessageType type, byte[] body)
    {
        MessageHeader header = new MessageHeader
        {
            MessageId = messageId,
            BodyLength = body?.Length ?? 0,
            Type = type
        };

        // 计算总长度
        int headerSize = Marshal.SizeOf(typeof(MessageHeader));
        int totalSize = headerSize + header.BodyLength;

        byte[] data = new byte[totalSize];

        // 序列化头部
        IntPtr ptr = Marshal.AllocHGlobal(headerSize);
        Marshal.StructureToPtr(header, ptr, false);
        Marshal.Copy(ptr, data, 0, headerSize);
        Marshal.FreeHGlobal(ptr);

        // 复制消息体
        if (body != null && body.Length > 0)
        {
            Buffer.BlockCopy(body, 0, data, headerSize, body.Length);
        }

        return data;
    }

    public static (MessageHeader header, byte[] body) DeserializeMessage(byte[] data)
    {
        int headerSize = Marshal.SizeOf(typeof(MessageHeader));

        // 反序列化头部
        MessageHeader header;
        IntPtr ptr = Marshal.AllocHGlobal(headerSize);
        Marshal.Copy(data, 0, ptr, headerSize);
        header = (MessageHeader)Marshal.PtrToStructure(ptr, typeof(MessageHeader));
        Marshal.FreeHGlobal(ptr);

        // 提取消息体
        byte[] body = new byte[header.BodyLength];
        if (header.BodyLength > 0)
        {
            Buffer.BlockCopy(data, headerSize, body, 0, header.BodyLength);
        }

        return (header, body);
    }
}

5.2 JSON协议实现

public class JsonProtocolHandler
{
    public class Message
    {
        public string Command { get; set; }
        public object Data { get; set; }
        public DateTime Timestamp { get; set; }
    }

    public byte[] SerializeMessage(Message message)
    {
        string json = JsonSerializer.Serialize(message);
        return Encoding.UTF8.GetBytes(json);
    }

    public Message DeserializeMessage(byte[] data)
    {
        string json = Encoding.UTF8.GetString(data);
        return JsonSerializer.Deserialize<Message>(json);
    }

    public async Task SendMessageAsync(NetworkStream stream, Message message)
    {
        byte[] data = SerializeMessage(message);

        // 先发送数据长度
        byte[] lengthBytes = BitConverter.GetBytes(data.Length);
        await stream.WriteAsync(lengthBytes, 0, 4);

        // 发送实际数据
        await stream.WriteAsync(data, 0, data.Length);
    }

    public async Task<Message> ReceiveMessageAsync(NetworkStream stream)
    {
        // 读取数据长度
        byte[] lengthBytes = new byte[4];
        await stream.ReadAsync(lengthBytes, 0, 4);
        int dataLength = BitConverter.ToInt32(lengthBytes, 0);

        // 读取实际数据
        byte[] data = new byte[dataLength];
        int bytesRead = 0;
        while (bytesRead < dataLength)
        {
            bytesRead += await stream.ReadAsync(data, bytesRead, dataLength - bytesRead);
        }

        return DeserializeMessage(data);
    }
}

第 6 章:网络通信模式

6.1 请求-响应模式

public class RequestResponseClient
{
    private TcpClient client;
    private NetworkStream stream;
    private JsonProtocolHandler protocolHandler;

    public RequestResponseClient()
    {
        protocolHandler = new JsonProtocolHandler();
    }

    public async Task<T> SendRequestAsync<T>(string command, object data)
    {
        try
        {
            var request = new JsonProtocolHandler.Message
            {
                Command = command,
                Data = data,
                Timestamp = DateTime.UtcNow
            };

            await protocolHandler.SendMessageAsync(stream, request);

            var response = await protocolHandler.ReceiveMessageAsync(stream);
            return JsonSerializer.Deserialize<T>(response.Data.ToString());
        }
        catch (Exception ex)
        {
            Console.WriteLine($"请求错误: {ex.Message}");
            throw;
        }
    }
}

6.2 发布-订阅模式

public class PubSubServer
{
    private TcpListener listener;
    private List<TcpClient> subscribers = new List<TcpClient>();
    private readonly object lockObject = new object();

    public async Task StartAsync(string ipAddress, int port)
    {
        IPAddress localAddr = IPAddress.Parse(ipAddress);
        listener = new TcpListener(localAddr, port);
        listener.Start();

        Console.WriteLine("发布-订阅服务器已启动");

        while (true)
        {
            TcpClient client = await listener.AcceptTcpClientAsync();
            _ = HandleSubscriberAsync(client);
        }
    }

    private async Task HandleSubscriberAsync(TcpClient client)
    {
        lock (lockObject)
        {
            subscribers.Add(client);
        }

        try
        {
            NetworkStream stream = client.GetStream();
            byte[] buffer = new byte[1024];

            while (client.Connected)
            {
                // 处理订阅者消息
                int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
                if (bytesRead == 0) break;

                // 这里可以处理订阅者的订阅请求等
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"处理订阅者错误: {ex.Message}");
        }
        finally
        {
            lock (lockObject)
            {
                subscribers.Remove(client);
            }
            client.Close();
        }
    }

    public async Task PublishAsync(string topic, object data)
    {
        var message = new JsonProtocolHandler.Message
        {
            Command = "PUBLISH",
            Data = new { Topic = topic, Content = data },
            Timestamp = DateTime.UtcNow
        };

        byte[] messageData = new JsonProtocolHandler().SerializeMessage(message);

        List<TcpClient> currentSubscribers;
        lock (lockObject)
        {
            currentSubscribers = new List<TcpClient>(subscribers);
        }

        var tasks = currentSubscribers.Select(async client =>
        {
            try
            {
                if (client.Connected)
                {
                    NetworkStream stream = client.GetStream();
                    await stream.WriteAsync(messageData, 0, messageData.Length);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"发布消息错误: {ex.Message}");
            }
        });

        await Task.WhenAll(tasks);
    }
}

第 7 章:性能优化与最佳实践

7.1 连接池管理

public class ConnectionPool : IDisposable
{
    private ConcurrentBag<TcpClient> connections;
    private string server;
    private int port;
    private int maxPoolSize;
    private SemaphoreSlim semaphore;

    public ConnectionPool(string server, int port, int maxPoolSize = 10)
    {
        this.server = server;
        this.port = port;
        this.maxPoolSize = maxPoolSize;
        connections = new ConcurrentBag<TcpClient>();
        semaphore = new SemaphoreSlim(maxPoolSize, maxPoolSize);
    }

    public async Task<TcpClient> GetConnectionAsync()
    {
        await semaphore.WaitAsync();

        if (connections.TryTake(out TcpClient client) && client.Connected)
        {
            return client;
        }

        // 创建新连接
        client = new TcpClient();
        await client.ConnectAsync(server, port);
        return client;
    }

    public void ReturnConnection(TcpClient client)
    {
        if (client.Connected)
        {
            connections.Add(client);
        }
        else
        {
            client.Dispose();
        }
        semaphore.Release();
    }

    public void Dispose()
    {
        foreach (var client in connections)
        {
            client?.Close();
            client?.Dispose();
        }
        connections.Clear();
        semaphore.Dispose();
    }
}

7.2 缓冲区管理

public class BufferManager
{
    private byte[] bufferPool;
    private int currentIndex;
    private int bufferSize;
    private readonly object lockObject = new object();

    public BufferManager(int totalBytes, int bufferSize)
    {
        this.bufferSize = bufferSize;
        bufferPool = new byte[totalBytes];
    }

    public bool SetBuffer(SocketAsyncEventArgs args)
    {
        lock (lockObject)
        {
            if ((bufferPool.Length - currentIndex) < bufferSize)
            {
                return false;
            }

            args.SetBuffer(bufferPool, currentIndex, bufferSize);
            currentIndex += bufferSize;
            return true;
        }
    }

    public void FreeBuffer(SocketAsyncEventArgs args)
    {
        // 在实际应用中可能需要更复杂的内存管理
        args.SetBuffer(null, 0, 0);
    }
}

第 8 章:安全与加密

8.1 SSL/TLS 加密通信

public class SslTcpClient
{
    public async Task ConnectWithSslAsync(string server, int port)
    {
        TcpClient client = new TcpClient();
        await client.ConnectAsync(server, port);

        using (SslStream sslStream = new SslStream(client.GetStream(), false, ValidateServerCertificate, null))
        {
            try
            {
                await sslStream.AuthenticateAsClientAsync(server);

                // 加密通信
                byte[] message = Encoding.UTF8.GetBytes("Hello Secure Server");
                await sslStream.WriteAsync(message, 0, message.Length);

                byte[] buffer = new byte[1024];
                int bytesRead = await sslStream.ReadAsync(buffer, 0, buffer.Length);
                string response = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                Console.WriteLine($"安全服务器回复: {response}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"SSL通信错误: {ex.Message}");
            }
        }
    }

    private bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        // 在实际应用中应该进行严格的证书验证
        return sslPolicyErrors == SslPolicyErrors.None;
    }
}

8.2 数据加密传输

public class SecureDataTransmitter
{
    private Aes aesAlg;

    public SecureDataTransmitter()
    {
        aesAlg = Aes.Create();
        aesAlg.KeySize = 256;
        aesAlg.GenerateKey();
        aesAlg.GenerateIV();
    }

    public byte[] EncryptData(string plainText)
    {
        using (ICryptoTransform encryptor = aesAlg.CreateEncryptor())
        {
            byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
            return encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length);
        }
    }

    public string DecryptData(byte[] cipherText)
    {
        using (ICryptoTransform decryptor = aesAlg.CreateDecryptor())
        {
            byte[] plainBytes = decryptor.TransformFinalBlock(cipherText, 0, cipherText.Length);
            return Encoding.UTF8.GetString(plainBytes);
        }
    }

    public void Dispose()
    {
        aesAlg?.Dispose();
    }
}

第 9 章:实战案例

9.1 聊天服务器实现

public class ChatServer
{
    private TcpListener listener;
    private List<ChatClient> clients = new List<ChatClient>();
    private readonly object lockObject = new object();

    public async Task StartAsync(string ipAddress, int port)
    {
        IPAddress localAddr = IPAddress.Parse(ipAddress);
        listener = new TcpListener(localAddr, port);
        listener.Start();

        Console.WriteLine("聊天服务器已启动");

        while (true)
        {
            TcpClient client = await listener.AcceptTcpClientAsync();
            ChatClient chatClient = new ChatClient(client, this);

            lock (lockObject)
            {
                clients.Add(chatClient);
            }

            _ = chatClient.StartHandlingAsync();
        }
    }

    public async Task BroadcastMessageAsync(string message, ChatClient sender)
    {
        List<ChatClient> currentClients;
        lock (lockObject)
        {
            currentClients = new List<ChatClient>(clients);
        }

        var tasks = currentClients.Where(c => c != sender).Select(async client =>
        {
            await client.SendMessageAsync(message);
        });

        await Task.WhenAll(tasks);
    }

    public void RemoveClient(ChatClient client)
    {
        lock (lockObject)
        {
            clients.Remove(client);
        }
    }
}

public class ChatClient
{
    private TcpClient client;
    private NetworkStream stream;
    private ChatServer server;
    private string username;

    public ChatClient(TcpClient client, ChatServer server)
    {
        this.client = client;
        this.server = server;
        this.stream = client.GetStream();
    }

    public async Task StartHandlingAsync()
    {
        try
        {
            // 获取用户名
            byte[] buffer = new byte[1024];
            int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
            username = Encoding.UTF8.GetString(buffer, 0, bytesRead);

            Console.WriteLine($"{username} 加入了聊天室");

            await server.BroadcastMessageAsync($"{username} 加入了聊天室", this);

            while (client.Connected)
            {
                bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
                if (bytesRead == 0) break;

                string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                Console.WriteLine($"{username}: {message}");

                await server.BroadcastMessageAsync($"{username}: {message}", this);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"处理客户端 {username} 错误: {ex.Message}");
        }
        finally
        {
            server.RemoveClient(this);
            client.Close();
            await server.BroadcastMessageAsync($"{username} 离开了聊天室", this);
            Console.WriteLine($"{username} 离开了聊天室");
        }
    }

    public async Task SendMessageAsync(string message)
    {
        byte[] data = Encoding.UTF8.GetBytes(message);
        await stream.WriteAsync(data, 0, data.Length);
    }
}

第 10 章:常见问题与解决方案

10.1 连接管理问题

问题:连接泄漏

// 解决方案:使用using语句确保资源释放
using (TcpClient client = new TcpClient())
using (NetworkStream stream = client.GetStream())
{
    // 使用连接
}

10.2 性能优化技巧

// 使用SocketAsyncEventArgs进行高性能I/O
public class HighPerformanceSocket
{
    public void Start()
    {
        Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        SocketAsyncEventArgs args = new SocketAsyncEventArgs();

        args.Completed += OnSocketOperationCompleted;
        args.SetBuffer(new byte[8192], 0, 8192);

        if (!socket.AcceptAsync(args))
        {
            OnSocketOperationCompleted(socket, args);
        }
    }

    private void OnSocketOperationCompleted(object sender, SocketAsyncEventArgs e)
    {
        // 处理完成的操作
    }
}

10.3 错误处理最佳实践

public class RobustSocketClient
{
    public async Task<bool> ConnectWithRetryAsync(string server, int port, int maxRetries = 3)
    {
        for (int attempt = 1; attempt <= maxRetries; attempt++)
        {
            try
            {
                using (TcpClient client = new TcpClient())
                {
                    await client.ConnectAsync(server, port);
                    return true;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"连接尝试 {attempt} 失败: {ex.Message}");
                if (attempt == maxRetries) return false;

                await Task.Delay(1000 * attempt); // 指数退避
            }
        }
        return false;
    }
}

本指南涵盖了C# Socket编程的所有核心概念和实战技巧,从基础TCP/UDP通信到高级的网络编程模式,适合从入门到精通的完整学习路径。

posted @ 2025-10-18 14:35  【唐】三三  阅读(2)  评论(0)    收藏  举报