云计算百科
云计算领域专业知识百科平台

我将基于之前的TCP/UDP网络小助手,扩展支持多客户端(TCP模式下服务器处理多个客户端连接)和文件传输功能(支持发送和接收文件)

我将基于之前的TCP/UDP网络小助手,扩展支持多客户端(TCP模式下服务器处理多个客户端连接)和文件传输功能(支持发送和接收文件)。以下是更新的开发步骤和完整源码,包含多客户端管理和文件传输逻辑。

 更新开发步骤 1. 多客户端支持:    – 修改TCP服务器,使用`List<TcpClient>`存储所有连接的客户端。    – 为每个客户端开启独立的异步任务处理消息,广播消息给其他客户端。    – 添加客户端断开连接的检测和清理逻辑。

2. 文件传输功能:    – 添加文件选择按钮和文件路径显示,使用`OpenFileDialog`选择文件。    – 实现文件传输协议:发送文件前发送文件名和文件大小,接收端解析并保存。    – 支持TCP和UDP文件传输(TCP使用流,UDP分块发送)。

3. 界面更新:    – 添加文件选择按钮、文件路径文本框和发送文件按钮。    – 显示文件传输进度和状态。

4. 逻辑优化:    – 增加消息类型区分(文本消息和文件传输)。    – 改进异常处理,确保多客户端和文件传输的稳定性。

5. 测试:    – 测试多客户端连接和消息广播。    – 测试文件传输(小文件和大文件),验证完整性和正确性。

 更新源码 以下是扩展后的C# WinForms程序源码,包含多客户端支持和文件传输功能。

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace NetworkAssistant
{
    public partial class Form1 : Form
    {
        private TcpListener tcpListener;
        private TcpClient tcpClient;
        private UdpClient udpClient;
        private List<TcpClient> tcpClients = new List<TcpClient>();
        private bool isServerRunning;
        private bool isClientConnected;
        private OpenFileDialog openFileDialog;

        public Form1()
        {
            InitializeComponent();
            openFileDialog = new OpenFileDialog();
        }

        // 窗体初始化
        private void InitializeComponent()
        {
            this.comboBoxProtocol = new ComboBox();
            this.labelIP = new Label();
            this.textBoxIP = new TextBox();
            this.labelPort = new Label();
            this.textBoxPort = new TextBox();
            this.buttonStartServer = new Button();
            this.buttonConnectClient = new Button();
            this.textBoxSend = new TextBox();
            this.buttonSend = new Button();
            this.textBoxReceive = new TextBox();
            this.buttonClear = new Button();
            this.buttonSelectFile = new Button();
            this.textBoxFilePath = new TextBox();
            this.buttonSendFile = new Button();

            // comboBoxProtocol
            this.comboBoxProtocol.Items.AddRange(new object[] { "TCP", "UDP" });
            this.comboBoxProtocol.Location = new System.Drawing.Point(20, 20);
            this.comboBoxProtocol.Size = new System.Drawing.Size(100, 21);
            this.comboBoxProtocol.SelectedIndex = 0;

            // labelIP
            this.labelIP.Text = "IP Address:";
            this.labelIP.Location = new System.Drawing.Point(20, 50);
            this.labelIP.Size = new System.Drawing.Size(60, 20);

            // textBoxIP
            this.textBoxIP.Text = "127.0.0.1";
            this.textBoxIP.Location = new System.Drawing.Point(90, 50);
            this.textBoxIP.Size = new System.Drawing.Size(150, 20);

            // labelPort
            this.labelPort.Text = "Port:";
            this.labelPort.Location = new System.Drawing.Point(20, 80);
            this.labelPort.Size = new System.Drawing.Size(60, 20);

            // textBoxPort
            this.textBoxPort.Text = "8080";
            this.textBoxPort.Location = new System.Drawing.Point(90, 80);
            this.textBoxPort.Size = new System.Drawing.Size(150, 20);

            // buttonStartServer
            this.buttonStartServer.Text = "Start Server";
            this.buttonStartServer.Location = new System.Drawing.Point(20, 110);
            this.buttonStartServer.Size = new System.Drawing.Size(100, 30);
            this.buttonStartServer.Click += new EventHandler(this.buttonStartServer_Click);

            // buttonConnectClient
            this.buttonConnectClient.Text = "Connect Client";
            this.buttonConnectClient.Location = new System.Drawing.Point(140, 110);
            this.buttonConnectClient.Size = new System.Drawing.Size(100, 30);
            this.buttonConnectClient.Click += new EventHandler(this.buttonConnectClient_Click);

            // textBoxSend
            this.textBoxSend.Location = new System.Drawing.Point(20, 150);
            this.textBoxSend.Size = new System.Drawing.Size(300, 50);
            this.textBoxSend.Multiline = true;

            // buttonSend
            this.buttonSend.Text = "Send Text";
            this.buttonSend.Location = new System.Drawing.Point(330, 150);
            this.buttonSend.Size = new System.Drawing.Size(80, 50);
            this.buttonSend.Click += new EventHandler(this.buttonSend_Click);

            // buttonSelectFile
            this.buttonSelectFile.Text = "Select File";
            this.buttonSelectFile.Location = new System.Drawing.Point(20, 210);
            this.buttonSelectFile.Size = new System.Drawing.Size(80, 30);
            this.buttonSelectFile.Click += new EventHandler(this.buttonSelectFile_Click);

            // textBoxFilePath
            this.textBoxFilePath.Location = new System.Drawing.Point(110, 210);
            this.textBoxFilePath.Size = new System.Drawing.Size(210, 20);
            this.textBoxFilePath.ReadOnly = true;

            // buttonSendFile
            this.buttonSendFile.Text = "Send File";
            this.buttonSendFile.Location = new System.Drawing.Point(330, 210);
            this.buttonSendFile.Size = new System.Drawing.Size(80, 30);
            this.buttonSendFile.Click += new EventHandler(this.buttonSendFile_Click);

            // textBoxReceive
            this.textBoxReceive.Location = new System.Drawing.Point(20, 250);
            this.textBoxReceive.Size = new System.Drawing.Size(390, 150);
            this.textBoxReceive.Multiline = true;
            this.textBoxReceive.ReadOnly = true;

            // buttonClear
            this.buttonClear.Text = "Clear";
            this.buttonClear.Location = new System.Drawing.Point(20, 410);
            this.buttonClear.Size = new System.Drawing.Size(80, 30);
            this.buttonClear.Click += new EventHandler(this.buttonClear_Click);

            // Form
            this.Text = "TCP/UDP Network Assistant";
            this.Size = new System.Drawing.Size(450, 480);
            this.Controls.Add(this.comboBoxProtocol);
            this.Controls.Add(this.labelIP);
            this.Controls.Add(this.textBoxIP);
            this.Controls.Add(this.labelPort);
            this.Controls.Add(this.textBoxPort);
            this.Controls.Add(this.buttonStartServer);
            this.Controls.Add(this.buttonConnectClient);
            this.Controls.Add(this.textBoxSend);
            this.Controls.Add(this.buttonSend);
            this.Controls.Add(this.buttonSelectFile);
            this.Controls.Add(this.textBoxFilePath);
            this.Controls.Add(this.buttonSendFile);
            this.Controls.Add(this.textBoxReceive);
            this.Controls.Add(this.buttonClear);
        }

        // 启动服务器
        private async void buttonStartServer_Click(object sender, EventArgs e)
        {
            if (isServerRunning)
            {
                MessageBox.Show("Server is already running!");
                return;
            }

            try
            {
                string ip = textBoxIP.Text;
                int port = int.Parse(textBoxPort.Text);
                isServerRunning = true;
                buttonStartServer.Enabled = false;

                if (comboBoxProtocol.SelectedItem.ToString() == "TCP")
                {
                    await StartTcpServer(ip, port);
                }
                else
                {
                    await StartUdpServer(ip, port);
                }
            }
            catch (Exception ex)
            {
                isServerRunning = false;
                buttonStartServer.Enabled = true;
                MessageBox.Show($"Error starting server: {ex.Message}");
            }
        }

        // TCP服务器(支持多客户端)
        private async Task StartTcpServer(string ip, int port)
        {
            tcpListener = new TcpListener(IPAddress.Parse(ip), port);
            tcpListener.Start();
            AppendReceiveText("TCP Server started…");

            while (isServerRunning)
            {
                try
                {
                    TcpClient client = await tcpListener.AcceptTcpClientAsync();
                    lock (tcpClients)
                    {
                        tcpClients.Add(client);
                    }
                    AppendReceiveText($"Client connected. Total clients: {tcpClients.Count}");
                    _ = HandleTcpClient(client); // 异步处理客户端
                }
                catch (Exception ex)
                {
                    AppendReceiveText($"Server error: {ex.Message}");
                    break;
                }
            }
        }

        // 处理TCP客户端
        private async Task HandleTcpClient(TcpClient client)
        {
            try
            {
                using (NetworkStream stream = client.GetStream())
                {
                    byte[] buffer = new byte[1024];
                    while (isServerRunning)
                    {
                        int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
                        if (bytesRead == 0) break;

                        // 解析消息类型
                        string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                        if (message.StartsWith("FILE:"))
                        {
                            await ReceiveFileTcp(stream, message);
                        }
                        else
                        {
                            AppendReceiveText($"Received: {message}");
                            await BroadcastTcpMessage(message, client);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                AppendReceiveText($"Client error: {ex.Message}");
            }
            finally
            {
                lock (tcpClients)
                {
                    tcpClients.Remove(client);
                }
                client.Close();
                AppendReceiveText($"Client disconnected. Total clients: {tcpClients.Count}");
            }
        }

        // 广播消息给所有TCP客户端
        private async Task BroadcastTcpMessage(string message, TcpClient sender)
        {
            byte[] buffer = Encoding.UTF8.GetBytes(message);
            lock (tcpClients)
            {
                foreach (var client in tcpClients)
                {
                    if (client != sender)
                    {
                        try
                        {
                            NetworkStream stream = client.GetStream();
                            stream.WriteAsync(buffer, 0, buffer.Length);
                        }
                        catch { }
                    }
                }
            }
        }

        // UDP服务器
        private async Task StartUdpServer(string ip, int port)
        {
            udpClient = new UdpClient(port);
            AppendReceiveText("UDP Server started…");

            while (isServerRunning)
            {
                try
                {
                    UdpReceiveResult result = await udpClient.ReceiveAsync();
                    string message = Encoding.UTF8.GetString(result.Buffer);
                    if (message.StartsWith("FILE:"))
                    {
                        await ReceiveFileUdp(result.RemoteEndPoint);
                    }
                    else
                    {
                        AppendReceiveText($"Received from {result.RemoteEndPoint}: {message}");
                    }
                }
                catch (Exception ex)
                {
                    AppendReceiveText($"Server error: {ex.Message}");
                    break;
                }
            }
        }

        // 连接客户端
        private async void buttonConnectClient_Click(object sender, EventArgs e)
        {
            if (isClientConnected)
            {
                MessageBox.Show("Client is already connected!");
                return;
            }

            try
            {
                string ip = textBoxIP.Text;
                int port = int.Parse(textBoxPort.Text);
                isClientConnected = true;
                buttonConnectClient.Enabled = false;

                if (comboBoxProtocol.SelectedItem.ToString() == "TCP")
                {
                    tcpClient = new TcpClient();
                    await tcpClient.ConnectAsync(ip, port);
                    AppendReceiveText("Connected to TCP server.");
                    _ = ReceiveTcpClientMessages();
                }
                else
                {
                    udpClient = new UdpClient();
                    AppendReceiveText("UDP Client ready.");
                }
            }
            catch (Exception ex)
            {
                isClientConnected = false;
                buttonConnectClient.Enabled = true;
                MessageBox.Show($"Error connecting: {ex.Message}");
            }
        }

        // 接收TCP客户端消息
        private async Task ReceiveTcpClientMessages()
        {
            try
            {
                using (NetworkStream stream = tcpClient.GetStream())
                {
                    byte[] buffer = new byte[1024];
                    while (isClientConnected)
                    {
                        int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
                        if (bytesRead == 0) break;

                        string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                        if (message.StartsWith("FILE:"))
                        {
                            await ReceiveFileTcp(stream, message);
                        }
                        else
                        {
                            AppendReceiveText($"Received: {message}");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                AppendReceiveText($"Client error: {ex.Message}");
            }
            finally
            {
                isClientConnected = false;
                buttonConnectClient.Enabled = true;
                tcpClient?.Close();
                AppendReceiveText("Disconnected from server.");
            }
        }

        // 发送文本消息
        private async void buttonSend_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(textBoxSend.Text))
            {
                MessageBox.Show("Please enter a message to send.");
                return;
            }

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

                if (comboBoxProtocol.SelectedItem.ToString() == "TCP")
                {
                    if (isClientConnected && tcpClient != null)
                    {
                        NetworkStream stream = tcpClient.GetStream();
                        await stream.WriteAsync(buffer, 0, buffer.Length);
                        AppendReceiveText($"Sent: {message}");
                    }
                    else
                    {
                        MessageBox.Show("Client not connected!");
                    }
                }
                else
                {
                    if (udpClient != null)
                    {
                        string ip = textBoxIP.Text;
                        int port = int.Parse(textBoxPort.Text);
                        await udpClient.SendAsync(buffer, buffer.Length, ip, port);
                        AppendReceiveText($"Sent: {message}");
                    }
                    else
                    {
                        MessageBox.Show("UDP client not initialized!");
                    }
                }

                textBoxSend.Clear();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error sending message: {ex.Message}");
            }
        }

        // 选择文件
        private void buttonSelectFile_Click(object sender, EventArgs e)
        {
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                textBoxFilePath.Text = openFileDialog.FileName;
            }
        }

        // 发送文件
        private async void buttonSendFile_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(textBoxFilePath.Text) || !File.Exists(textBoxFilePath.Text))
            {
                MessageBox.Show("Please select a valid file.");
                return;
            }

            try
            {
                string filePath = textBoxFilePath.Text;
                string fileName = Path.GetFileName(filePath);
                long fileSize = new FileInfo(filePath).Length;

                if (comboBoxProtocol.SelectedItem.ToString() == "TCP")
                {
                    if (isClientConnected && tcpClient != null)
                    {
                        await SendFileTcp(filePath, fileName, fileSize);
                        AppendReceiveText($"Sent file: {fileName}");
                    }
                    else
                    {
                        MessageBox.Show("Client not connected!");
                    }
                }
                else
                {
                    if (udpClient != null)
                    {
                        await SendFileUdp(filePath, fileName, fileSize);
                        AppendReceiveText($"Sent file: {fileName}");
                    }
                    else
                    {
                        MessageBox.Show("UDP client not initialized!");
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error sending file: {ex.Message}");
            }
        }

        // 发送文件(TCP)
        private async Task SendFileTcp(string filePath, string fileName, long fileSize)
        {
            NetworkStream stream = tcpClient.GetStream();
            // 发送文件头
            string header = $"FILE:{fileName}:{fileSize}";
            byte[] headerBytes = Encoding.UTF8.GetBytes(header);
            await stream.WriteAsync(headerBytes, 0, headerBytes.Length);

            // 发送文件内容
            using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                byte[] buffer = new byte[8192];
                int bytesRead;
                while ((bytesRead = await fs.ReadAsync(buffer, 0, buffer.Length)) > 0)
                {
                    await stream.WriteAsync(buffer, 0, bytesRead);
                }
            }
        }

        // 接收文件(TCP)
        private async Task ReceiveFileTcp(NetworkStream stream, string header)
        {
            try
            {
                string[] parts = header.Split(':');
                string fileName = parts[1];
                long fileSize = long.Parse(parts[2]);
                string savePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), fileName);

                using (FileStream fs = new FileStream(savePath, FileMode.Create, FileAccess.Write))
                {
                    byte[] buffer = new byte[8192];
                    long totalBytesRead = 0;
                    while (totalBytesRead < fileSize)
                    {
                        int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
                        if (bytesRead == 0) break;
                        await fs.WriteAsync(buffer, 0, bytesRead);
                        totalBytesRead += bytesRead;
                    }
                }

                AppendReceiveText($"Received file: {fileName}, saved to {savePath}");
            }
            catch (Exception ex)
            {
                AppendReceiveText($"Error receiving file: {ex.Message}");
            }
        }

        // 发送文件(UDP)
        private async Task SendFileUdp(string filePath, string fileName, long fileSize)
        {
            string ip = textBoxIP.Text;
            int port = int.Parse(textBoxPort.Text);
            // 发送文件头
            string header = $"FILE:{fileName}:{fileSize}";
            byte[] headerBytes = Encoding.UTF8.GetBytes(header);
            await udpClient.SendAsync(headerBytes, headerBytes.Length, ip, port);

            // 发送文件内容
            using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                byte[] buffer = new byte[8192];
                int bytesRead;
                while ((bytesRead = await fs.ReadAsync(buffer, 0, buffer.Length)) > 0)
                {
                    await udpClient.SendAsync(buffer, bytesRead, ip, port);
                }
            }
        }

        // 接收文件(UDP)
        private async Task ReceiveFileUdp(IPEndPoint remoteEndPoint)
        {
            try
            {
                UdpReceiveResult headerResult = await udpClient.ReceiveAsync();
                string header = Encoding.UTF8.GetString(headerResult.Buffer);
                string[] parts = header.Split(':');
                string fileName = parts[1];
                long fileSize = long.Parse(parts[2]);
                string savePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), fileName);

                using (FileStream fs = new FileStream(savePath, FileMode.Create, FileAccess.Write))
                {
                    long totalBytesRead = 0;
                    while (totalBytesRead < fileSize)
                    {
                        UdpReceiveResult result = await udpClient.ReceiveAsync();
                        await fs.WriteAsync(result.Buffer, 0, result.Buffer.Length);
                        totalBytesRead += result.Buffer.Length;
                    }
                }

                AppendReceiveText($"Received file: {fileName}, saved to {savePath}");
            }
            catch (Exception ex)
            {
                AppendReceiveText($"Error receiving file: {ex.Message}");
            }
        }

        // 清空接收消息
        private void buttonClear_Click(object sender, EventArgs e)
        {
            textBoxReceive.Clear();
        }

        // 追加接收消息到文本框
        private void AppendReceiveText(string text)
        {
            if (textBoxReceive.InvokeRequired)
            {
                textBoxReceive.Invoke(new Action(() => textBoxReceive.AppendText(text + Environment.NewLine)));
            }
            else
            {
                textBoxReceive.AppendText(text + Environment.NewLine);
            }
        }

        // 窗体关闭时清理资源
        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            isServerRunning = false;
            isClientConnected = false;
            tcpListener?.Stop();
            lock (tcpClients)
            {
                foreach (var client in tcpClients)
                {
                    client.Close();
                }
                tcpClients.Clear();
            }
            tcpClient?.Close();
            udpClient?.Close();
            base.OnFormClosing(e);
        }

        private ComboBox comboBoxProtocol;
        private Label labelIP;
        private TextBox textBoxIP;
        private Label labelPort;
        private TextBox textBoxPort;
        private Button buttonStartServer;
        private Button buttonConnectClient;
        private TextBox textBoxSend;
        private Button buttonSend;
        private TextBox textBoxReceive;
        private Button buttonClear;
        private Button buttonSelectFile;
        private TextBox textBoxFilePath;
        private Button buttonSendFile;
    }
}

 使用说明 1. 运行程序:    – 在Visual Studio中创建新WinForms项目,替换`Form1.cs`为上述代码。    – 编译并运行。

2. 操作步骤:    – 选择协议:选择`TCP`或`UDP`。    – 输入IP和端口:默认`127.0.0.1:8080`,可修改。    – 启动服务器:点击“Start Server”,TCP模式支持多客户端连接。    – 连接客户端:在多个实例中点击“Connect Client”(TCP需要连接,UDP直接发送)。    – 发送文本:输入文本,点击“Send Text”,TCP广播给所有客户端,UDP发送到指定IP。    – 发送文件:点击“Select File”选择文件,点击“Send File”传输,文件保存到接收端桌面。    – 查看消息:文本和文件传输状态显示在接收文本框,点击“Clear”清空。

3. 注意事项:    – TCP多客户端:服务器维护所有客户端连接,消息广播给其他客户端,断开连接自动清理。    – 文件传输:文件保存到桌面,UDP传输可能因丢包导致不完整,建议大文件使用TCP。    – 端口占用:确保端口未被占用,异常情况会显示提示。

 测试建议 – 多客户端测试:    – 启动一个服务器(TCP模式),运行多个客户端实例连接,发送文本消息,验证广播功能。    – 断开一个客户端,检查服务器是否正确清理并更新客户端计数。 – 文件传输测试:    – 测试小文件(如文本文件)和大文件(如图片或视频),验证文件完整性。    – 在TCP和UDP模式下分别测试,比较可靠性(TCP更稳定)。 – 网络测试:    – 在不同机器上运行,修改IP为目标服务器IP,测试跨设备通信。 – 异常测试:    – 模拟网络中断或端口占用,验证错误提示和程序稳定性。

 扩展说明 – 多客户端:TCP服务器使用`List<TcpClient>`管理客户端,线程安全地添加和移除客户端,支持消息广播。 – 文件传输:通过发送文件头(文件名和大小)实现可靠传输,TCP使用流传输,UDP分块发送(可能丢包)。 – 局限性:    – UDP文件传输未实现重传机制,大文件可能不完整。    – 未添加进度条显示文件传输进度。 – 进一步改进:    – 添加文件传输进度条。    – 实现UDP重传机制。    – 支持文件夹传输或加密传输。

这个版本的网络小助手已支持多客户端和文件传输,适合学习和测试网络通信。如需特定功能扩展,请联系我252439060

赞(0)
未经允许不得转载:网硕互联帮助中心 » 我将基于之前的TCP/UDP网络小助手,扩展支持多客户端(TCP模式下服务器处理多个客户端连接)和文件传输功能(支持发送和接收文件)
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!