C# WinForm实现Socket异步通讯的完整指南

一、基础环境搭建

1.1 创建WinForm项目

  1. 打开Visual Studio,创建新的Windows Forms应用程序项目
  2. 添加必要的UI控件:
    • 两个TextBox(用于IP和端口输入)
    • 两个Button(启动服务/连接服务)
    • 一个RichTextBox(显示通讯日志)
    • 一个TextBox(消息输入)
    • 发送按钮
图片[1]_C# WinForm实现Socket异步通讯的完整指南_知途无界

1.2 添加必要的命名空间

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

二、服务端实现

2.1 服务端核心类

public class AsyncSocketServer
{
    private Socket _serverSocket;
    private RichTextBox _logBox;
    private List<Socket> _clientSockets = new List<Socket>();
    
    public AsyncSocketServer(RichTextBox logBox)
    {
        _logBox = logBox;
    }
    
    public void Start(string ip, int port)
    {
        try
        {
            IPAddress ipAddress = IPAddress.Parse(ip);
            IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port);
            
            _serverSocket = new Socket(ipAddress.AddressFamily, 
                                     SocketType.Stream, 
                                     ProtocolType.Tcp);
            
            _serverSocket.Bind(localEndPoint);
            _serverSocket.Listen(10);
            
            AppendLog($"服务已启动,监听 {ip}:{port}");
            
            // 开始异步接受客户端连接
            _serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket);
        }
        catch (Exception ex)
        {
            AppendLog($"服务启动失败: {ex.Message}");
        }
    }
    
    private void AcceptCallback(IAsyncResult ar)
    {
        try
        {
            Socket listener = (Socket)ar.AsyncState;
            Socket clientSocket = listener.EndAccept(ar);
            
            _clientSockets.Add(clientSocket);
            AppendLog($"客户端连接: {clientSocket.RemoteEndPoint}");
            
            // 开始接收数据
            StateObject state = new StateObject();
            state.WorkSocket = clientSocket;
            clientSocket.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0,
                                    new AsyncCallback(ReceiveCallback), state);
            
            // 继续接受其他客户端连接
            _serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket);
        }
        catch (Exception ex)
        {
            AppendLog($"接受连接错误: {ex.Message}");
        }
    }
    
    private void ReceiveCallback(IAsyncResult ar)
    {
        try
        {
            StateObject state = (StateObject)ar.AsyncState;
            Socket clientSocket = state.WorkSocket;
            
            int bytesRead = clientSocket.EndReceive(ar);
            
            if (bytesRead > 0)
            {
                string content = Encoding.UTF8.GetString(state.Buffer, 0, bytesRead);
                AppendLog($"收到消息: {content}");
                
                // 广播消息给所有客户端
                Broadcast(content);
                
                // 继续接收数据
                clientSocket.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0,
                                        new AsyncCallback(ReceiveCallback), state);
            }
            else
            {
                // 客户端断开连接
                _clientSockets.Remove(clientSocket);
                clientSocket.Shutdown(SocketShutdown.Both);
                clientSocket.Close();
                AppendLog("客户端断开连接");
            }
        }
        catch (Exception ex)
        {
            AppendLog($"接收数据错误: {ex.Message}");
        }
    }
    
    private void Broadcast(string message)
    {
        byte[] byteData = Encoding.UTF8.GetBytes(message);
        
        foreach (Socket client in _clientSockets)
        {
            try
            {
                client.BeginSend(byteData, 0, byteData.Length, 0,
                                new AsyncCallback(SendCallback), client);
            }
            catch
            {
                // 处理发送失败的客户端
                _clientSockets.Remove(client);
            }
        }
    }
    
    private void SendCallback(IAsyncResult ar)
    {
        try
        {
            Socket client = (Socket)ar.AsyncState;
            int bytesSent = client.EndSend(ar);
        }
        catch (Exception ex)
        {
            AppendLog($"发送数据错误: {ex.Message}");
        }
    }
    
    private void AppendLog(string message)
    {
        if (_logBox.InvokeRequired)
        {
            _logBox.Invoke(new Action<string>(AppendLog), message);
        }
        else
        {
            _logBox.AppendText($"{DateTime.Now}: {message}\n");
        }
    }
}

// 辅助类,用于保存状态
public class StateObject
{
    public Socket WorkSocket = null;
    public const int BufferSize = 1024;
    public byte[] Buffer = new byte[BufferSize];
}

三、客户端实现

3.1 客户端核心类

public class AsyncSocketClient
{
    private Socket _clientSocket;
    private RichTextBox _logBox;
    
    public AsyncSocketClient(RichTextBox logBox)
    {
        _logBox = logBox;
    }
    
    public void Connect(string ip, int port)
    {
        try
        {
            IPAddress ipAddress = IPAddress.Parse(ip);
            IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
            
            _clientSocket = new Socket(ipAddress.AddressFamily,
                                      SocketType.Stream,
                                      ProtocolType.Tcp);
            
            // 异步连接
            _clientSocket.BeginConnect(remoteEP, 
                                      new AsyncCallback(ConnectCallback), 
                                      _clientSocket);
        }
        catch (Exception ex)
        {
            AppendLog($"连接错误: {ex.Message}");
        }
    }
    
    private void ConnectCallback(IAsyncResult ar)
    {
        try
        {
            Socket client = (Socket)ar.AsyncState;
            client.EndConnect(ar);
            
            AppendLog($"已连接到服务器 {client.RemoteEndPoint}");
            
            // 开始接收数据
            StateObject state = new StateObject();
            state.WorkSocket = client;
            client.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0,
                              new AsyncCallback(ReceiveCallback), state);
        }
        catch (Exception ex)
        {
            AppendLog($"连接回调错误: {ex.Message}");
        }
    }
    
    private void ReceiveCallback(IAsyncResult ar)
    {
        try
        {
            StateObject state = (StateObject)ar.AsyncState;
            Socket client = state.WorkSocket;
            
            int bytesRead = client.EndReceive(ar);
            
            if (bytesRead > 0)
            {
                string content = Encoding.UTF8.GetString(state.Buffer, 0, bytesRead);
                AppendLog($"收到消息: {content}");
                
                // 继续接收数据
                client.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0,
                                  new AsyncCallback(ReceiveCallback), state);
            }
            else
            {
                // 服务器断开连接
                client.Shutdown(SocketShutdown.Both);
                client.Close();
                AppendLog("服务器断开连接");
            }
        }
        catch (Exception ex)
        {
            AppendLog($"接收数据错误: {ex.Message}");
        }
    }
    
    public void Send(string message)
    {
        try
        {
            byte[] byteData = Encoding.UTF8.GetBytes(message);
            
            _clientSocket.BeginSend(byteData, 0, byteData.Length, 0,
                                  new AsyncCallback(SendCallback), _clientSocket);
        }
        catch (Exception ex)
        {
            AppendLog($"发送数据错误: {ex.Message}");
        }
    }
    
    private void SendCallback(IAsyncResult ar)
    {
        try
        {
            Socket client = (Socket)ar.AsyncState;
            int bytesSent = client.EndSend(ar);
        }
        catch (Exception ex)
        {
            AppendLog($"发送回调错误: {ex.Message}");
        }
    }
    
    private void AppendLog(string message)
    {
        if (_logBox.InvokeRequired)
        {
            _logBox.Invoke(new Action<string>(AppendLog), message);
        }
        else
        {
            _logBox.AppendText($"{DateTime.Now}: {message}\n");
        }
    }
}

四、UI界面整合

4.1 服务端界面代码

public partial class ServerForm : Form
{
    private AsyncSocketServer _server;
    
    public ServerForm()
    {
        InitializeComponent();
    }
    
    private void btnStart_Click(object sender, EventArgs e)
    {
        string ip = txtIP.Text;
        int port = int.Parse(txtPort.Text);
        
        _server = new AsyncSocketServer(rtbLog);
        _server.Start(ip, port);
    }
    
    private void btnSend_Click(object sender, EventArgs e)
    {
        if (_server != null && !string.IsNullOrEmpty(txtMessage.Text))
        {
            _server.Broadcast(txtMessage.Text);
            rtbLog.AppendText($"{DateTime.Now}: 发送消息: {txtMessage.Text}\n");
            txtMessage.Clear();
        }
    }
}

4.2 客户端界面代码

public partial class ClientForm : Form
{
    private AsyncSocketClient _client;
    
    public ClientForm()
    {
        InitializeComponent();
    }
    
    private void btnConnect_Click(object sender, EventArgs e)
    {
        string ip = txtIP.Text;
        int port = int.Parse(txtPort.Text);
        
        _client = new AsyncSocketClient(rtbLog);
        _client.Connect(ip, port);
    }
    
    private void btnSend_Click(object sender, EventArgs e)
    {
        if (_client != null && !string.IsNullOrEmpty(txtMessage.Text))
        {
            _client.Send(txtMessage.Text);
            rtbLog.AppendText($"{DateTime.Now}: 发送消息: {txtMessage.Text}\n");
            txtMessage.Clear();
        }
    }
}

五、通讯流程详解

5.1 服务端工作流程

sequenceDiagram
    participant UI as 服务端界面
    participant Server as 异步服务端
    participant Client as 客户端
    
    UI->>Server: 启动服务(IP, Port)
    Server->>Server: 创建Socket并绑定
    Server->>Server: 开始监听(BeginAccept)
    
    Client->>Server: 连接请求
    Server->>Server: 接受连接(BeginAccept回调)
    Server->>Client: 确认连接
    Server->>Server: 开始接收数据(BeginReceive)
    
    Client->>Server: 发送数据
    Server->>Server: 接收数据(BeginReceive回调)
    Server->>UI: 显示接收的消息
    Server->>Client: 广播消息给所有客户端

5.2 客户端工作流程

sequenceDiagram
    participant UI as 客户端界面
    participant Client as 异步客户端
    participant Server as 服务端
    
    UI->>Client: 连接服务(IP, Port)
    Client->>Server: 发起连接(BeginConnect)
    Server->>Client: 接受连接
    Client->>UI: 显示连接成功
    Client->>Client: 开始接收数据(BeginReceive)
    
    UI->>Client: 发送消息
    Client->>Server: 发送数据(BeginSend)
    Server->>Client: 广播消息
    Client->>UI: 显示接收的消息

六、高级功能扩展

6.1 心跳检测机制

// 在服务端StateObject类中添加
public DateTime LastActiveTime { get; set; }

// 修改ReceiveCallback
private void ReceiveCallback(IAsyncResult ar)
{
    // ...原有代码...
    state.LastActiveTime = DateTime.Now;
    // ...原有代码...
}

// 添加心跳检测方法
private void CheckHeartbeat()
{
    while (true)
    {
        Thread.Sleep(30000); // 每30秒检测一次
        
        foreach (Socket client in _clientSockets.ToList())
        {
            var state = (StateObject)client.AsyncState;
            if ((DateTime.Now - state.LastActiveTime).TotalSeconds > 60)
            {
                // 超时断开
                _clientSockets.Remove(client);
                client.Shutdown(SocketShutdown.Both);
                client.Close();
                AppendLog($"客户端 {client.RemoteEndPoint} 心跳超时断开");
            }
        }
    }
}

6.2 消息加密传输

// 添加加密解密方法
private string Encrypt(string plainText)
{
    // 使用AES等加密算法
    byte[] encryptedBytes = ...;
    return Convert.ToBase64String(encryptedBytes);
}

private string Decrypt(string cipherText)
{
    // 解密过程
    byte[] cipherBytes = Convert.FromBase64String(cipherText);
    return Encoding.UTF8.GetString(decryptedBytes);
}

// 修改发送和接收方法
private void ReceiveCallback(IAsyncResult ar)
{
    // ...原有代码...
    string encryptedContent = Encoding.UTF8.GetString(state.Buffer, 0, bytesRead);
    string content = Decrypt(encryptedContent);
    // ...原有代码...
}

private void Broadcast(string message)
{
    string encryptedMessage = Encrypt(message);
    byte[] byteData = Encoding.UTF8.GetBytes(encryptedMessage);
    // ...原有代码...
}

七、常见问题解决方案

7.1 跨线程UI更新问题

// 使用Control.Invoke确保线程安全
private void AppendLog(string message)
{
    if (_logBox.InvokeRequired)
    {
        _logBox.Invoke(new Action<string>(AppendLog), message);
    }
    else
    {
        _logBox.AppendText($"{DateTime.Now}: {message}\n");
    }
}

7.2 Socket异常处理

// 所有Socket操作都应包含try-catch
try
{
    // Socket操作代码
}
catch (SocketException se)
{
    AppendLog($"Socket异常: {se.SocketErrorCode} - {se.Message}");
}
catch (Exception ex)
{
    AppendLog($"错误: {ex.Message}");
}

7.3 资源释放

// 在Form关闭时释放资源
protected override void OnFormClosing(FormClosingEventArgs e)
{
    base.OnFormClosing(e);
    
    try
    {
        if (_server != null)
        {
            foreach (Socket client in _server.ClientSockets)
            {
                client.Shutdown(SocketShutdown.Both);
                client.Close();
            }
            _server.ServerSocket.Close();
        }
        
        if (_client != null)
        {
            _client.ClientSocket.Shutdown(SocketShutdown.Both);
            _client.ClientSocket.Close();
        }
    }
    catch { }
}

八、性能优化建议

8.1 缓冲区管理

// 使用更大的缓冲区提高性能
public class StateObject
{
    public const int BufferSize = 8192; // 8KB缓冲区
    // ...其他成员...
}

// 接收数据时调整
client.BeginReceive(state.Buffer, 0, StateObject.BufferSize, SocketFlags.None,
                  new AsyncCallback(ReceiveCallback), state);

8.2 异步发送队列

// 添加发送队列避免并发问题
private Queue<byte[]> _sendQueue = new Queue<byte[]>();
private bool _isSending = false;

public void Send(string message)
{
    byte[] data = Encoding.UTF8.GetBytes(message);
    lock (_sendQueue)
    {
        _sendQueue.Enqueue(data);
        
        if (!_isSending)
        {
            _isSending = true;
            ThreadPool.QueueUserWorkItem(SendNext);
        }
    }
}

private void SendNext(object state)
{
    byte[] data;
    lock (_sendQueue)
    {
        if (_sendQueue.Count == 0)
        {
            _isSending = false;
            return;
        }
        data = _sendQueue.Dequeue();
    }
    
    try
    {
        _clientSocket.BeginSend(data, 0, data.Length, SocketFlags.None,
                              new AsyncCallback(SendCallback), null);
    }
    catch
    {
        // 处理错误
        _isSending = false;
    }
}

private void SendCallback(IAsyncResult ar)
{
    try
    {
        _clientSocket.EndSend(ar);
        ThreadPool.QueueUserWorkItem(SendNext);
    }
    catch
    {
        _isSending = false;
    }
}

九、完整项目结构

9.1 项目文件结构

SocketCommunication/
├── Server/
│   ├── ServerForm.cs
│   ├── AsyncSocketServer.cs
│   └── StateObject.cs
├── Client/
│   ├── ClientForm.cs
│   ├── AsyncSocketClient.cs
│   └── StateObject.cs
└── Common/
    ├── EncryptionHelper.cs
    └── Logger.cs

9.2 类关系图

classDiagram
    class ServerForm{
        +AsyncSocketServer _server
        +btnStart_Click()
        +btnSend_Click()
    }
    
    class AsyncSocketServer{
        -Socket _serverSocket
        -List~Socket~ _clientSockets
        +Start()
        -AcceptCallback()
        -ReceiveCallback()
        -Broadcast()
    }
    
    class ClientForm{
        +AsyncSocketClient _client
        +btnConnect_Click()
        +btnSend_Click()
    }
    
    class AsyncSocketClient{
        -Socket _clientSocket
        +Connect()
        -ConnectCallback()
        -ReceiveCallback()
        +Send()
    }
    
    class StateObject{
        +Socket WorkSocket
        +byte[] Buffer
        +DateTime LastActiveTime
    }
    
    ServerForm --> AsyncSocketServer
    ClientForm --> AsyncSocketClient
    AsyncSocketServer --> StateObject
    AsyncSocketClient --> StateObject

关键实现要点​:

  1. 使用异步模式避免UI阻塞
  2. 状态对象保持回调上下文
  3. 跨线程UI更新必须使用Invoke
  4. 所有Socket操作都需要异常处理
  5. 合理管理Socket资源生命周期

扩展建议​:

  1. 添加消息协议(如长度前缀)
  2. 实现断线重连机制
  3. 增加用户认证功能
  4. 支持文件传输
  5. 添加消息历史记录
© 版权声明
THE END
喜欢就点个赞,支持一下吧!
点赞40 分享
评论 抢沙发
头像
欢迎您留下评论!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容