C#教程

关注公众号 jb51net

关闭
首页 > 软件编程 > C#教程 > WinForm异步TCP通信

WinForm中异步TCP通信的正确打开方式

作者:小码编匠

软件开发中,网络通信是实现分布式系统、远程控制和实时数据交换的核心技术之一,TCP 作为传输层中最常用的协议,以其面向连接、可靠传输、字节流通信的特点,本文将结合一个完整的WinForm 应用程序实例,给大家介绍WinForm中异步TCP通信的正确打开方式

前言

软件开发中,网络通信是实现分布式系统、远程控制和实时数据交换的核心技术之一。TCP(Transmission Control Protocol) 作为传输层中最常用的协议,以其面向连接、可靠传输、字节流通信的特点,广泛应用于对数据完整性和顺序性要求较高的场景。

本文将结合一个完整的 ** WinForm 应用程序实例**,深入解析基于 .NET 6 + Visual Studio 2022 的 TCP 客户端-服务器通信实现过程,涵盖界面设计、核心代码逻辑、线程安全处理、资源管理以及底层 TCP 协议机制,帮助开发快速掌握实际项目中的网络编程技巧。

一、效果展示

项目包含两个独立的窗体应用:服务端(Form1)客户端(Form2),通过 TCP 协议实现双向通信。

服务端界面

服务端可监听指定端口,接收多个客户端连接,并广播消息给所有在线客户端。

客户端界面

客户端输入服务端IP与端口后发起连接,支持发送消息并实时接收来自服务端或其他客户端的广播信息。

二、开发环境与工具

开发工具:Visual Studio 2022

编程语言:C# (.NET 6)

应用类型:Windows Forms App

关键技术

服务端主界面

客户端连接与通信界面

三、核心代码

1、服务端(Form1)实现

服务端负责监听端口、接受客户端连接,并实现消息广播机制

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

namespace WinFormsApp3
{
    public partial class Form1 : Form
    {
        private TcpListener server;
        private List<TcpClient> clients = new List<TcpClient>();

        public Form1()
        {
            InitializeComponent();
        }

        // 启动服务端监听
        private async void btnStart_Click(object sender, EventArgs e)
        {
            server = new TcpListener(IPAddress.Any, int.Parse(tbServerIP.Text));
            server.Start();
            UpdateUI("服务端已启动...");
            _ = AcceptClientsAsync(); // 启动异步接受连接

            // 打开客户端测试窗体(仅用于演示)
            Form2 form2 = new Form2();
            form2.ShowDialog();
        }

        // 异步接受客户端连接
        private async Task AcceptClientsAsync()
        {
            while (true)
            {
                TcpClient client = await server.AcceptTcpClientAsync();
                clients.Add(client);
                UpdateUI($"客户端已连接:{client.Client.RemoteEndPoint}");
                _ = HandleClientAsync(client); // 为每个客户端启动独立处理任务
            }
        }

        // 处理单个客户端通信
        private async Task HandleClientAsync(TcpClient client)
        {
            NetworkStream stream = client.GetStream();
            byte[] buffer = new byte[1024];

            try
            {
                while (true)
                {
                    int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
                    if (bytesRead == 0) break; // 客户端断开

                    string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                    UpdateUI($"接收:{message}");

                    // 广播消息给所有已连接客户端
                    foreach (var c in clients.Where(c => c.Connected))
                    {
                        await c.GetStream().WriteAsync(buffer, 0, bytesRead);
                    }
                }
            }
            catch (Exception ex)
            {
                UpdateUI($"客户端异常断开:{ex.Message}");
            }
            finally
            {
                clients.Remove(client);
                client.Close();
                UpdateUI("客户端已断开连接");
            }
        }

        // 线程安全地更新UI
        private void UpdateUI(string message)
        {
            if (InvokeRequired)
            {
                Invoke(new Action(() => UpdateUI(message)));
                return;
            }
            txtLog.AppendText($"{DateTime.Now:yyyy-MM-dd HH:mm:ss}: {message}\r\n");
        }

        // 窗体关闭时释放资源
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            server?.Stop();
            foreach (var client in clients)
            {
                client?.Close();
            }
            clients.Clear();
        }
    }
}

2、客户端(Form2)实现

客户端负责连接服务端、发送消息并接收服务端广播。

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

namespace WinFormsApp3
{
    public partial class Form2 : Form
    {
        private TcpClient client;
        private NetworkStream stream;

        public Form2()
        {
            InitializeComponent();
        }

        // 连接服务端
        private async void btnConnect_Click(object sender, EventArgs e)
        {
            try
            {
                client = new TcpClient();
                await client.ConnectAsync(tbServerIP.Text, int.Parse(tbServerPor.Text));
                stream = client.GetStream();
                UpdateUI("已成功连接到服务端");
                _ = ReceiveDataAsync(); // 启动异步接收
            }
            catch (Exception ex)
            {
                UpdateUI($"连接失败:{ex.Message}");
            }
        }

        // 异步接收数据
        private async Task ReceiveDataAsync()
        {
            byte[] buffer = new byte[1024];
            try
            {
                while (true)
                {
                    int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
                    if (bytesRead == 0) break;

                    string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                    UpdateUI($"接收:{message}");
                }
            }
            catch
            {
                UpdateUI("与服务端断开连接");
            }
            finally
            {
                client?.Close();
            }
        }

        // 发送消息
        private async void btnSend_Click(object sender, EventArgs e)
        {
            if (stream == null || !client.Connected)
            {
                UpdateUI("尚未连接到服务端");
                return;
            }

            string message = txtMessage.Text;
            byte[] data = Encoding.UTF8.GetBytes(message);
            await stream.WriteAsync(data, 0, data.Length);
            UpdateUI($"发送:{message}");
            txtMessage.Clear();
        }

        // 线程安全更新UI
        private void UpdateUI(string message)
        {
            if (InvokeRequired)
            {
                Invoke(new Action(() => UpdateUI(message)));
                return;
            }
            txtLog.AppendText($"{DateTime.Now:yyyy-MM-dd HH:mm:ss}: {message}\r\n");
        }

        // 关闭窗体时清理资源
        private void Form2_FormClosing(object sender, FormClosingEventArgs e)
        {
            client?.Close();
        }
    }
}

四、关键技术

1、线程安全与UI更新

由于网络操作在后台线程中执行,直接更新 WinForms 控件会引发跨线程异常。

使用 InvokeRequiredInvoke 方法确保 UI 操作在主线程中执行。

private void UpdateUI(string message)
{
    if (InvokeRequired)
    {
        Invoke(new Action(() => UpdateUI(message)));
        return;
    }
    // 安全更新UI
}

2、资源释放与异常处理

3、异步编程提升响应性

采用 async/await 模式进行非阻塞 I/O 操作,避免界面卡顿,提升用户体验。

五、TCP协议核心机制

1、三次握手建立连接(Three-way Handshake)

步骤发送方报文状态变化
1客户端SYN=1, seq=xSYN-SENT
2服务端SYN=1, ACK=1, seq=y, ack=x+1SYN-RCVD
3客户端ACK=1, ack=y+1ESTABLISHED

握手成功后,双方进入数据传输阶段。

2、数据传输机制

3、四次挥手终止连接(Four-way Wave-off)

步骤描述
1主动关闭方发送 FIN
2被动方回复 ACK,进入 CLOSE-WAIT
3被动方发送 FIN
4主动方回复 ACK,进入 TIME-WAIT,等待超时后关闭

六、TCP协议特点总结

特性说明
可靠性校验和、重传、确认机制确保数据完整
面向连接通信前需建立连接,结束后释放
字节流服务无消息边界,需应用层处理粘包/拆包
全双工通信双向同时收发数据
端口多路复用通过端口号区分不同应用服务

七、应用场景

1、远程调试与管理

如充电桩、工业设备通过 TCP长连接 实现远程监控与指令下发。

2、高可靠性数据传输

HTTP/HTTPS、FTP、SMTP 等应用层协议均基于 TCP。

3、即时通讯系统

聊天室、消息推送、在线游戏等实时交互场景。

4、文件传输服务

大文件可靠传输,支持断点续传。

总结

本文通过一个完整的 WinForm TCP通信项目,系统地展示了从界面设计、核心代码实现到底层协议原理的全过程。该案例不仅适用于学习网络编程基础,也可作为企业级通信模块的原型参考。

掌握 TCP Socket 编程,是构建稳定、高效分布式系统的基石。结合现代异步编程模型与线程安全机制,开发者能够轻松实现高性能的网络应用。

以上就是WinForm中异步TCP通信的正确打开方式的详细内容,更多关于WinForm异步TCP通信的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文