效果图
在这里插入图片描述
实现具体的代码:
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;
using System.Windows.Forms.VisualStyles;

namespace WinFormsApp1
{
public partial class Form2 : Form
{

    private TcpClient client;
    private NetworkStream stream;
    private CancellationTokenSource cts; // 用于控制接收循环的取消

    private TcpListener server;
    private TcpClient clientd;
    private NetworkStream streamd;
    public Form2()
    {
        InitializeComponent();
    }

    private void Form2_Load(object sender, EventArgs e)
    {

    }

    private void label1_Click(object sender, EventArgs e)
    {

    }

    private async void button1_Click(object sender, EventArgs e)
    {
        client = new TcpClient();
        string ip = textBox2.Text.Trim().ToString();
        int port = Convert.ToInt32(textBox3.Text.Trim().ToString());
        await client.ConnectAsync(ip, port);
        stream = client.GetStream();
        textBoxStatus.AppendText("Connected to server.\r\n");

        // 初始化 CancellationTokenSource 并启动接收循环
        cts = new CancellationTokenSource();
        Task.Run(() => ListenForResponses(cts.Token), cts.Token);

    }

    private async Task ListenForResponses(CancellationToken token)
    {
        byte[] buffer = new byte[1024];
        int bytesRead;

        try
        {
            while (!token.IsCancellationRequested)
            {
                if (stream.DataAvailable) // 检查是否有数据可用(可选,但可以提高效率)
                {
                    bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, token);
                    string response = Encoding.ASCII.GetString(buffer, 0, bytesRead);

                    // 由于我们在非UI线程上,我们需要使用Invoke来更新UI
                    UpdateStatus($"Received: {response}\r\n");
                }
                // 如果没有DataAvailable检查,这里可以添加一些延迟以避免忙等待
                // 例如:await Task.Delay(100, token);
            }
        }
        catch (OperationCanceledException) when (token.IsCancellationRequested)
        {
            // 这是预期的取消,不需要处理异常
        }
        catch (Exception ex)
        {
            // 处理其他可能的异常,例如流已关闭
            UpdateStatus($"Error: {ex.Message}\r\n");
        }
        finally
        {
            // 通常,这里不应该关闭流,因为用户可能希望重新连接
            // 但为了完整性,这里保留了这个finally块来演示如何关闭流(尽管这样做可能会导致问题)
            // 在实际应用中,您应该在DisconnectButton_Click中处理这些关闭操作
        }
    }

    private void UpdateStatus(string text)
    {
        // 使用Invoke来确保线程安全地更新UI
        if (textBoxStatus.InvokeRequired)
        {
            textBoxStatus.Invoke(new Action<string>(UpdateStatus), text);
        }
        else
        {
            textBoxStatus.AppendText(text);
        }
    }


    private async void button2_Click(object sender, EventArgs e)
    {
        string message = textBoxMessage.Text;
        byte[] data = Encoding.ASCII.GetBytes(message);
        Task.Run(async () => await stream.WriteAsync(data, 0, data.Length));
        textBoxStatus.AppendText($"Sent: {message}\r\n");
    }

    private void button3_Click(object sender, EventArgs e)
    {
        // 取消接收操作
        cts?.Cancel();
        cts = null; // 重置CancellationTokenSource(如果需要重新连接)

        // 关闭流和客户端
        stream?.Close();
        client?.Close();
        textBoxStatus.AppendText("Disconnected from server.\r\n");
    }

    private async void button4_Click(object sender, EventArgs e)
    {
        server = new TcpListener(IPAddress.Any, 5000);
        server.Start();
        textBoxStatusd.AppendText("Server started...\r\n");

        TcpClient clientHandler = await server.AcceptTcpClientAsync();
        clientd = clientHandler;
        streamd = clientd.GetStream();

        Task.Run(() => ListenForMessages());
    }


    private async void ListenForMessages()
    {
        byte[] buffer = new byte[1024];
        int bytesRead;

        while ((bytesRead = await streamd.ReadAsync(buffer, 0, buffer.Length)) != 0)
        {
            string message = Encoding.ASCII.GetString(buffer, 0, bytesRead);

            // 检查是否需要跨线程调用
            if (textBoxStatusd.InvokeRequired)
            {
                // 使用 Invoke 在 UI 线程上执行操作
                textBoxStatusd.Invoke(new Action(() =>
                {
                    textBoxStatusd.AppendText($"Received: {message}\r\n");
                }));
            }
            else
            {
                // 如果已经在 UI 线程上,则直接更新
                textBoxStatusd.AppendText($"Received: {message}\r\n");
            }
            // 发送回应
            string response = "Message received"; // 可以根据需要修改回应内容
            await SendResponseAsync(response);
        }
    }

    private void button5_Click(object sender, EventArgs e)
    {
        if (clientd != null)
        {
            streamd.Close();
            clientd.Close();
        }
        server.Stop();
        textBoxStatusd.AppendText("Server stopped.\r\n");
    }

    private async Task SendResponseAsync(string response)
    {
        byte[] responseBytes = Encoding.ASCII.GetBytes(response);
        await streamd.WriteAsync(responseBytes, 0, responseBytes.Length);

        // 使用 Invoke 或 BeginInvoke 来确保在 UI 线程上更新文本框
        if (textBoxStatusd.InvokeRequired)
        {
            textBoxStatusd.Invoke(new Action(() =>
            {
                textBoxStatusd.AppendText($"Send: {response}\r\n");
            }));
        }
        else
        {
            textBoxStatusd.AppendText($"Send: {response}\r\n");
        }
    }

    private async void button6_Click(object sender, EventArgs e)
    {
        // 发送回应
        string response = textBox4.Text.Trim().ToString(); // 可以根据需要修改回应内容
        await SendResponseAsync(response);
    }
}

}

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐