給我一個 C# Socket 的 client 端原始程式. /* #### OneTimeSocketClient.cs One time socket client 說明 Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp): 建立一個 TCP 連線。 Connect:連線到指定的 IP 和 Port。 Send / Receive:分別傳送和接收資料。 Shutdown / Close:結束連線並釋放資源。 */ using System; using System.Net; using System.Net.Sockets; using System.Text; class SocketClient { static void Main(string[] args) { // 伺服器 IP 和 Port string serverIp = "127.0.0.1"; int serverPort = 11000; try { // 建立 TCP/IP Socket Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 連接到伺服器 clientSocket.Connect(new IPEndPoint(IPAddress.Parse(serverIp), serverPort)); Console.WriteLine("連接到伺服器成功!"); // 傳送訊息 string message = "Hello, Server!"; byte[] messageBytes = Encoding.UTF8.GetBytes(message); clientSocket.Send(messageBytes); Console.WriteLine("傳送訊息: " + message); // 接收回應 byte[] buffer = new byte[1024]; int receivedLength = clientSocket.Receive(buffer); string response = Encoding.UTF8.GetString(buffer, 0, receivedLength); Console.WriteLine("接收到伺服器回應: " + response); // 關閉連線 clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Close(); } catch (Exception ex) { Console.WriteLine("發生錯誤: " + ex.Message); } Console.WriteLine("按任意鍵結束..."); Console.ReadKey(); } } /* #### OneClientService.cs 這個 Server 的流程: 綁定在本機 IP 127.0.0.1,port 11000。 等待客戶端連線。 收到客戶端訊息後,回傳一句話 "Hello from Server!"。 然後關閉該客戶端連線,等待下一個新的客戶端連進來。 這個版本的特點: 一旦有一個 client 連進來,server 會一直在 while (true) 內收資料。 如果 client 主動斷線(Receive 回傳 0),就離開 while 迴圈,關閉該 client 的連線。 每收一筆就「即時回應」給 client。 注意事項: Server 必須先啟動,再啟動 Client,不然 Client 會找不到 Server。 如果要在不同電腦測試,需要把 127.0.0.1 改成實際的 IP,並開啟防火牆或設定網路權限。 要不要我也補一版「可以連續收多次訊息」的進階 Server?(例如同一個 Client 多次傳訊息,而不是一次斷線)要的話跟我說 👍! 想要進一步了解嗎?例如「非同步版」(async/await)或「多個 client 同時連線」的版本? */ using System; using System.Net; using System.Net.Sockets; using System.Text; class SocketServer { static void Main(string[] args) { // 監聽的 IP 和 Port string localIp = "127.0.0.1"; int localPort = 11000; try { // 建立 TCP/IP Socket Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 綁定 IP 和 Port serverSocket.Bind(new IPEndPoint(IPAddress.Parse(localIp), localPort)); serverSocket.Listen(10); // 最多允許 10 個等待中的連線 Console.WriteLine($"伺服器啟動,監聽 {localIp}:{localPort}"); while (true) { Console.WriteLine("等待客戶端連線..."); Socket clientSocket = serverSocket.Accept(); // 接受一個連線 Console.WriteLine("客戶端已連線!"); // 接收資料 byte[] buffer = new byte[1024]; int receivedLength = clientSocket.Receive(buffer); string clientMessage = Encoding.UTF8.GetString(buffer, 0, receivedLength); Console.WriteLine("收到客戶端訊息: " + clientMessage); // 回應客戶端 string response = "Hello from Server!"; byte[] responseBytes = Encoding.UTF8.GetBytes(response); clientSocket.Send(responseBytes); Console.WriteLine("回傳訊息: " + response); // 關閉與客戶端的連線 clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Close(); Console.WriteLine("已關閉與客戶端的連線\n"); } } catch (Exception ex) { Console.WriteLine("發生錯誤: " + ex.Message); } Console.WriteLine("伺服器結束..."); Console.ReadKey(); } } /* 這個版本的特點: 一旦有一個 client 連進來,server 會一直在 while (true) 內收資料。 如果 client 主動斷線(Receive 回傳 0),就離開 while 迴圈,關閉該 client 的連線。 每收一筆就「即時回應」給 client。 #### MultiThreadService.cs 進階小提醒: 目前這版是單一 client,一個一個處理,如果要「多個 client 同時連線」要再加上 Thread 或 Task(非同步/多執行緒)。 如果 client 很多、頻繁收送,可以考慮用 async/await 或用 SocketAsyncEventArgs 做高效能伺服器。 要不要我也順便教你如何改成 支援多 client 同時連線(多執行緒版)? 要 支援多 client 同時連線(多執行緒版) 說明重點: serverSocket.Accept() 之後,對每個 client 都新開一條 Thread。 每個 client 都可以各自收發訊息,不會互相影響。 server 可以同時處理多個 client 並行通訊。 當 client 斷線,該 thread 自己結束,不會影響其他 client。 ⚡ 小提醒 用 Thread 的版本適合小型應用,如果 client 很多很多(例如幾百上千), 建議用 ThreadPool 或 async/await 非同步來更有效率管理資源。 若要做「大量併發連線」的 server,會建議進一步學 async Socket 或 SocketAsyncEventArgs。 */ using System; using System.Net; using System.Net.Sockets; using System.Text; class SocketServer { static void Main(string[] args) { // 監聽的 IP 和 Port string localIp = "127.0.0.1"; int localPort = 11000; try { // 建立 TCP/IP Socket Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 綁定 IP 和 Port serverSocket.Bind(new IPEndPoint(IPAddress.Parse(localIp), localPort)); serverSocket.Listen(10); // 最多允許10個等待中的連線 Console.WriteLine($"伺服器啟動,監聽 {localIp}:{localPort}"); while (true) { Console.WriteLine("等待客戶端連線..."); Socket clientSocket = serverSocket.Accept(); // 接受一個連線 Console.WriteLine("客戶端已連線!"); // 處理這個連進來的 client HandleClient(clientSocket); } } catch (Exception ex) { Console.WriteLine("發生錯誤: " + ex.Message); } Console.WriteLine("伺服器結束..."); Console.ReadKey(); } static void HandleClient(Socket clientSocket) { try { byte[] buffer = new byte[1024]; while (true) { // 等待接收資料 int receivedLength = clientSocket.Receive(buffer); if (receivedLength == 0) { // 表示 client 斷線 Console.WriteLine("客戶端已斷線。"); break; } string clientMessage = Encoding.UTF8.GetString(buffer, 0, receivedLength); Console.WriteLine("收到訊息: " + clientMessage); // 回應同樣的訊息(Echo) string response = $"Server 收到: {clientMessage}"; byte[] responseBytes = Encoding.UTF8.GetBytes(response); clientSocket.Send(responseBytes); Console.WriteLine("回傳訊息: " + response); } // 結束這個 client clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Close(); } catch (Exception ex) { Console.WriteLine("與客戶端通訊發生錯誤: " + ex.Message); } } } /* #### AsyncService.cs 要不要我也順便幫你做一版 async/await 非同步版 Socket Server? (可以讓 server 更輕量,不用一直開 thread,效能超好!) 要的話直接說「要 async/await 版」我就幫你準備!🚀 要一起也給你對應的 多 client 測試用小程式嗎?✅ (可以讓你一次開很多 client 測試 server) 要 async/await 版, 也要一起也給你對應的 多 client 測試用小程式. */ using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; class SocketServer { static void Main(string[] args) { // 監聽的 IP 和 Port string localIp = "127.0.0.1"; int localPort = 11000; try { // 建立 TCP/IP Socket Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 綁定 IP 和 Port serverSocket.Bind(new IPEndPoint(IPAddress.Parse(localIp), localPort)); serverSocket.Listen(100); // 最多允許100個等待中的連線 Console.WriteLine($"伺服器啟動,監聽 {localIp}:{localPort}"); while (true) { Console.WriteLine("等待客戶端連線..."); Socket clientSocket = serverSocket.Accept(); // 接受一個連線 Console.WriteLine($"新的客戶端已連線,來自 {clientSocket.RemoteEndPoint}"); // 為每個 client 啟動一個新的 Thread 處理 Thread clientThread = new Thread(() => HandleClient(clientSocket)); clientThread.Start(); } } catch (Exception ex) { Console.WriteLine("發生錯誤: " + ex.Message); } Console.WriteLine("伺服器結束..."); Console.ReadKey(); } static void HandleClient(Socket clientSocket) { try { byte[] buffer = new byte[1024]; while (true) { int receivedLength = clientSocket.Receive(buffer); if (receivedLength == 0) { Console.WriteLine($"客戶端 {clientSocket.RemoteEndPoint} 已斷線。"); break; } string clientMessage = Encoding.UTF8.GetString(buffer, 0, receivedLength); Console.WriteLine($"收到 {clientSocket.RemoteEndPoint} 的訊息: {clientMessage}"); // 回傳回去 string response = $"Server 收到: {clientMessage}"; byte[] responseBytes = Encoding.UTF8.GetBytes(response); clientSocket.Send(responseBytes); Console.WriteLine($"已回應 {clientSocket.RemoteEndPoint}"); } clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Close(); } catch (Exception ex) { Console.WriteLine($"與客戶端 {clientSocket.RemoteEndPoint} 通訊錯誤: {ex.Message}"); } } } /* #### AsyncSocketServer.cs 1️⃣ 【C# async/await 非同步版 Socket Server】 🧠 async/await server 特點: 連線時用 await AcceptAsync() 收資料用 await ReceiveAsync() 傳資料用 await SendAsync() 每個 client 用一個 Task(非 Thread),大量 client 也不會塞爆 CPU 超適合高併發測試! */ using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; class AsyncSocketServer { static async Task Main(string[] args) { string localIp = "127.0.0.1"; int localPort = 11000; var serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); serverSocket.Bind(new IPEndPoint(IPAddress.Parse(localIp), localPort)); serverSocket.Listen(100); Console.WriteLine($"伺服器啟動,監聽 {localIp}:{localPort}"); while (true) { Console.WriteLine("等待客戶端連線..."); Socket clientSocket = await serverSocket.AcceptAsync(); Console.WriteLine($"新的客戶端已連線:{clientSocket.RemoteEndPoint}"); // 開一個新的 Task 非同步處理這個 client _ = HandleClientAsync(clientSocket); } } static async Task HandleClientAsync(Socket clientSocket) { var buffer = new byte[1024]; try { while (true) { int receivedLength = await clientSocket.ReceiveAsync(buffer, SocketFlags.None); if (receivedLength == 0) { Console.WriteLine($"客戶端 {clientSocket.RemoteEndPoint} 已斷線。"); break; } string clientMessage = Encoding.UTF8.GetString(buffer, 0, receivedLength); Console.WriteLine($"收到 {clientSocket.RemoteEndPoint} 的訊息: {clientMessage}"); // 回傳訊息 string response = $"Server 收到: {clientMessage}"; byte[] responseBytes = Encoding.UTF8.GetBytes(response); await clientSocket.SendAsync(responseBytes, SocketFlags.None); Console.WriteLine($"已回應 {clientSocket.RemoteEndPoint}"); } } catch (Exception ex) { Console.WriteLine($"與客戶端 {clientSocket.RemoteEndPoint} 通訊發生錯誤: {ex.Message}"); } finally { clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Close(); } } } /* #### MultiClientTester.cs 2️⃣ 【多 client 測試小程式 (開很多個 client 同時連 server)】 📋 測試流程 啟動 Server(async/await 版)。 啟動 MultiClientTester,輸入想要開幾個 Client(例如 10 個或 100 個)。 每個 client 都會連上 Server 並送 5 次訊息。 Server 每次都即時回應。 */ using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; class MultiClientTester { static async Task Main(string[] args) { Console.Write("要啟動幾個 Client?:"); int clientCount = int.Parse(Console.ReadLine()); string serverIp = "127.0.0.1"; int serverPort = 11000; var tasks = new Task[clientCount]; for (int i = 0; i < clientCount; i++) { int clientId = i + 1; tasks[i] = Task.Run(async () => { await StartClientAsync(serverIp, serverPort, clientId); }); } await Task.WhenAll(tasks); Console.WriteLine("所有 Client 測試完成。按任意鍵離開。"); Console.ReadKey(); } static async Task StartClientAsync(string serverIp, int serverPort, int clientId) { try { var clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); await clientSocket.ConnectAsync(new IPEndPoint(IPAddress.Parse(serverIp), serverPort)); Console.WriteLine($"Client {clientId} 已連線"); for (int i = 0; i < 5; i++) // 每個 client 傳 5 次訊息 { string message = $"Client {clientId} 的訊息 {i + 1}"; byte[] messageBytes = Encoding.UTF8.GetBytes(message); await clientSocket.SendAsync(messageBytes, SocketFlags.None); byte[] buffer = new byte[1024]; int receivedLength = await clientSocket.ReceiveAsync(buffer, SocketFlags.None); string response = Encoding.UTF8.GetString(buffer, 0, receivedLength); Console.WriteLine($"Client {clientId} 收到回應: {response}"); await Task.Delay(500); // 模擬 client 每0.5秒傳一次 } clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Close(); } catch (Exception ex) { Console.WriteLine($"Client {clientId} 發生錯誤: {ex.Message}"); } } } /* 要不要我再給你一個 GUI 版的 多 Client 測試器?(用 Windows Form 或 WPF) 可以直接「按按鈕啟動一堆 Client」更好玩更直覺 😎 要的話跟我說「要 GUI 版測試器」!我可以順便做好範例給你!🚀 「要 GUI 版測試器」, 用 Windows Form. 【Form1.Designer.cs】裡的基本元件設定(範例) 你要加的控制元件大概是: TextBox 名稱:txtServerIp,Text 預設 127.0.0.1 TextBox 名稱:txtServerPort,Text 預設 11000 TextBox 名稱:txtClientCount,Text 預設 10 Button 名稱:btnStart,Text:開始測試 ListBox 名稱:listBoxLog (可以用拖曳方式拉一拉就完成了) 5️⃣ 【執行畫面示意】 當你按下「開始測試」按鈕,就會看到 listbox 裡像這樣: 開始啟動 10 個 Client... Client 1 收到回應: Server 收到: Client 1 的訊息 1 Client 2 收到回應: Server 收到: Client 2 的訊息 1 Client 1 收到回應: Server 收到: Client 1 的訊息 2 ... 所有 Client 測試完成! 這個 WinForm 測試器 支援同時發動 大量 client 可以看到 即時訊息回報 簡單直覺好操作 超級適合自己本機測試你的 Async Socket Server 穩定性、效能! */ using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace MultiClientTesterWinForm { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private async void btnStart_Click(object sender, EventArgs e) { string serverIp = txtServerIp.Text.Trim(); int serverPort = int.Parse(txtServerPort.Text.Trim()); int clientCount = int.Parse(txtClientCount.Text.Trim()); listBoxLog.Items.Clear(); listBoxLog.Items.Add($"開始啟動 {clientCount} 個 Client..."); var tasks = new Task[clientCount]; for (int i = 0; i < clientCount; i++) { int clientId = i + 1; tasks[i] = Task.Run(async () => await StartClientAsync(serverIp, serverPort, clientId)); } await Task.WhenAll(tasks); listBoxLog.Items.Add("所有 Client 測試完成!"); } private async Task StartClientAsync(string serverIp, int serverPort, int clientId) { try { var clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); await clientSocket.ConnectAsync(new IPEndPoint(IPAddress.Parse(serverIp), serverPort)); for (int i = 0; i < 5; i++) // 每個 client 傳5次 { string message = $"Client {clientId} 的訊息 {i + 1}"; byte[] messageBytes = Encoding.UTF8.GetBytes(message); await clientSocket.SendAsync(messageBytes, SocketFlags.None); byte[] buffer = new byte[1024]; int receivedLength = await clientSocket.ReceiveAsync(buffer, SocketFlags.None); string response = Encoding.UTF8.GetString(buffer, 0, receivedLength); AppendLog($"Client {clientId} 收到回應: {response}"); await Task.Delay(300); // 每300毫秒發一次 } clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Close(); } catch (Exception ex) { AppendLog($"Client {clientId} 錯誤: {ex.Message}"); } } private void AppendLog(string message) { if (listBoxLog.InvokeRequired) { listBoxLog.Invoke(new Action(AppendLog), message); } else { listBoxLog.Items.Add(message); listBoxLog.TopIndex = listBoxLog.Items.Count - 1; // 自動捲到最下面 } } } } /* 要不要我順便也教你加個「自訂每個 Client 傳幾次」或「自動重連斷線 Client」的進階功能? 要的話直接說:「要進階功能」就可以了!🔥 (我可以一次給你完整範例包)🚀 要幫你做一版專案打包給你下載嗎?(附上 .sln)方便直接開啟?✅ 「要進階功能」, 並打包給我下載, 附上 .sln, 方便直接開啟. */ ------------------------------------------------------ MultiClientTesterWinForm ├── Program.cs ├── Form1.cs ├── Form1.Designer.cs ├── Form1.resx Program.cs using System; using System.Windows.Forms; namespace MultiClientTesterWinForm { static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } } Form1.cs using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace MultiClientTesterWinForm { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private async void btnStart_Click(object sender, EventArgs e) { string serverIp = txtServerIp.Text.Trim(); int serverPort = int.Parse(txtServerPort.Text.Trim()); int clientCount = int.Parse(txtClientCount.Text.Trim()); int messagePerClient = int.Parse(txtMessagesPerClient.Text.Trim()); listBoxLog.Items.Clear(); listBoxLog.Items.Add($"開始啟動 {clientCount} 個 Client,每個傳送 {messagePerClient} 次..."); var tasks = new Task[clientCount]; for (int i = 0; i < clientCount; i++) { int clientId = i + 1; tasks[i] = Task.Run(async () => await StartClientAsync(serverIp, serverPort, clientId, messagePerClient)); } await Task.WhenAll(tasks); listBoxLog.Items.Add("所有 Client 測試完成!"); } private async Task StartClientAsync(string serverIp, int serverPort, int clientId, int messageCount) { int retry = 0; Socket clientSocket = null; while (retry < 3) { try { clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); await clientSocket.ConnectAsync(new IPEndPoint(IPAddress.Parse(serverIp), serverPort)); AppendLog($"Client {clientId} 已連線"); break; // 成功連線,離開 retry } catch { retry++; AppendLog($"Client {clientId} 第 {retry} 次連線失敗,重試中..."); await Task.Delay(1000); } } if (clientSocket == null || !clientSocket.Connected) { AppendLog($"Client {clientId} 無法連線,放棄。"); return; } try { for (int i = 0; i < messageCount; i++) { string message = $"Client {clientId} 的訊息 {i + 1}"; byte[] messageBytes = Encoding.UTF8.GetBytes(message); await clientSocket.SendAsync(messageBytes, SocketFlags.None); byte[] buffer = new byte[1024]; int receivedLength = await clientSocket.ReceiveAsync(buffer, SocketFlags.None); string response = Encoding.UTF8.GetString(buffer, 0, receivedLength); AppendLog($"Client {clientId} 收到回應: {response}"); await Task.Delay(300); // 每300ms發一次 } clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Close(); } catch (Exception ex) { AppendLog($"Client {clientId} 錯誤: {ex.Message}"); } } private void AppendLog(string message) { if (listBoxLog.InvokeRequired) { listBoxLog.Invoke(new Action(AppendLog), message); } else { listBoxLog.Items.Add(message); listBoxLog.TopIndex = listBoxLog.Items.Count - 1; } } } } Form1.Designer.cs namespace MultiClientTesterWinForm { partial class Form1 { private System.ComponentModel.IContainer components = null; protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } private void InitializeComponent() { this.txtServerIp = new System.Windows.Forms.TextBox(); this.txtServerPort = new System.Windows.Forms.TextBox(); this.txtClientCount = new System.Windows.Forms.TextBox(); this.txtMessagesPerClient = new System.Windows.Forms.TextBox(); this.btnStart = new System.Windows.Forms.Button(); this.listBoxLog = new System.Windows.Forms.ListBox(); this.SuspendLayout(); // // txtServerIp // this.txtServerIp.Location = new System.Drawing.Point(12, 12); this.txtServerIp.Name = "txtServerIp"; this.txtServerIp.Size = new System.Drawing.Size(120, 22); this.txtServerIp.TabIndex = 0; this.txtServerIp.Text = "127.0.0.1"; // // txtServerPort // this.txtServerPort.Location = new System.Drawing.Point(138, 12); this.txtServerPort.Name = "txtServerPort"; this.txtServerPort.Size = new System.Drawing.Size(60, 22); this.txtServerPort.TabIndex = 1; this.txtServerPort.Text = "11000"; // // txtClientCount // this.txtClientCount.Location = new System.Drawing.Point(204, 12); this.txtClientCount.Name = "txtClientCount"; this.txtClientCount.Size = new System.Drawing.Size(60, 22); this.txtClientCount.TabIndex = 2; this.txtClientCount.Text = "10"; // // txtMessagesPerClient // this.txtMessagesPerClient.Location = new System.Drawing.Point(270, 12); this.txtMessagesPerClient.Name = "txtMessagesPerClient"; this.txtMessagesPerClient.Size = new System.Drawing.Size(60, 22); this.txtMessagesPerClient.TabIndex = 3; this.txtMessagesPerClient.Text = "5"; // // btnStart // this.btnStart.Location = new System.Drawing.Point(336, 10); this.btnStart.Name = "btnStart"; this.btnStart.Size = new System.Drawing.Size(100, 25); this.btnStart.TabIndex = 4; this.btnStart.Text = "開始測試"; this.btnStart.UseVisualStyleBackColor = true; this.btnStart.Click += new System.EventHandler(this.btnStart_Click); // // listBoxLog // this.listBoxLog.FormattingEnabled = true; this.listBoxLog.ItemHeight = 12; this.listBoxLog.Location = new System.Drawing.Point(12, 40); this.listBoxLog.Name = "listBoxLog"; this.listBoxLog.Size = new System.Drawing.Size(424, 256); this.listBoxLog.TabIndex = 5; // // Form1 // this.ClientSize = new System.Drawing.Size(448, 310); this.Controls.Add(this.listBoxLog); this.Controls.Add(this.btnStart); this.Controls.Add(this.txtMessagesPerClient); this.Controls.Add(this.txtClientCount); this.Controls.Add(this.txtServerPort); this.Controls.Add(this.txtServerIp); this.Name = "Form1"; this.Text = "多Client 測試器 (WinForm版)"; this.ResumeLayout(false); this.PerformLayout(); } private System.Windows.Forms.TextBox txtServerIp; private System.Windows.Forms.TextBox txtServerPort; private System.Windows.Forms.TextBox txtClientCount; private System.Windows.Forms.TextBox txtMessagesPerClient; private System.Windows.Forms.Button btnStart; private System.Windows.Forms.ListBox listBoxLog; } } /* ✅ 注意事項 Visual Studio 建一個 Windows Forms App,名稱取 MultiClientTesterWinForm 把 Form1.cs、Form1.Designer.cs、Program.cs 貼上取代預設的。 可以直接 F5 執行! .NET Framework 4.7.2 或以上版本最佳,.NET 6/7 WinForm 也行。 🎯 進階功能說明 每個 Client 可以設定傳幾次訊息。 連線失敗時,自動重試 3 次。 全部非同步 Task 運行,不會卡住 UI。 #### MultiClientTesterWinForm statistics 要不要我也順便幫你加上: 顯示目前正在連線 / 正在發送 的進度條? 測試結束後輸出總耗時、傳送總數量、成功/失敗數? 如果要,直接說:「要加進階統計」,我可以再加一版更完整!🔥 要不要也給你一個 預設的 Async Socket Server .NET 範例配套一起跑?(如果你想快速驗證) 要的話直接回覆:「要 Server 範例」。🚀 要加進階統計, 也要 Server 範例. 好!你一次要兩個升級: ✅ 進階統計(傳送量、成功失敗、總耗時) ✅ 配套 Server 範例(可以直接搭配剛剛 Client 測試) 我來一個一個給你,很快! 📈 【新版】WinForm 加進階統計功能! ✅ 新增統計: 總傳送次數 成功次數 失敗次數 總耗時 ✅ 新增控制元件: Label lblStatus:顯示統計結果 (直接加在 Form 上就好,下面我會給更新過的 Form1.cs 和 Designer.cs) 更新後的 Form1.cs 主要差異 using System; using System.Diagnostics; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace MultiClientTesterWinForm { public partial class Form1 : Form { private int totalSend = 0; private int successCount = 0; private int failCount = 0; private Stopwatch stopwatch = new Stopwatch(); public Form1() { InitializeComponent(); } private async void btnStart_Click(object sender, EventArgs e) { string serverIp = txtServerIp.Text.Trim(); int serverPort = int.Parse(txtServerPort.Text.Trim()); int clientCount = int.Parse(txtClientCount.Text.Trim()); int messagePerClient = int.Parse(txtMessagesPerClient.Text.Trim()); listBoxLog.Items.Clear(); ResetStatistics(); stopwatch.Restart(); listBoxLog.Items.Add($"開始啟動 {clientCount} 個 Client,每個傳 {messagePerClient} 次..."); var tasks = new Task[clientCount]; for (int i = 0; i < clientCount; i++) { int clientId = i + 1; tasks[i] = Task.Run(async () => await StartClientAsync(serverIp, serverPort, clientId, messagePerClient)); } await Task.WhenAll(tasks); stopwatch.Stop(); ShowStatistics(); listBoxLog.Items.Add("所有 Client 測試完成!"); } private async Task StartClientAsync(string serverIp, int serverPort, int clientId, int messageCount) { int retry = 0; Socket clientSocket = null; while (retry < 3) { try { clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); await clientSocket.ConnectAsync(new IPEndPoint(IPAddress.Parse(serverIp), serverPort)); AppendLog($"Client {clientId} 已連線"); break; } catch { retry++; AppendLog($"Client {clientId} 第 {retry} 次連線失敗,重試中..."); await Task.Delay(1000); } } if (clientSocket == null || !clientSocket.Connected) { AppendLog($"Client {clientId} 無法連線,放棄。"); IncreaseFail(); return; } try { for (int i = 0; i < messageCount; i++) { string message = $"Client {clientId} 的訊息 {i + 1}"; byte[] messageBytes = Encoding.UTF8.GetBytes(message); await clientSocket.SendAsync(messageBytes, SocketFlags.None); IncreaseTotal(); byte[] buffer = new byte[1024]; int receivedLength = await clientSocket.ReceiveAsync(buffer, SocketFlags.None); string response = Encoding.UTF8.GetString(buffer, 0, receivedLength); AppendLog($"Client {clientId} 收到回應: {response}"); IncreaseSuccess(); await Task.Delay(300); } clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Close(); } catch (Exception ex) { AppendLog($"Client {clientId} 錯誤: {ex.Message}"); IncreaseFail(); } } private void AppendLog(string message) { if (listBoxLog.InvokeRequired) { listBoxLog.Invoke(new Action(AppendLog), message); } else { listBoxLog.Items.Add(message); listBoxLog.TopIndex = listBoxLog.Items.Count - 1; } } private void IncreaseTotal() { Invoke(new Action(() => totalSend++)); } private void IncreaseSuccess() { Invoke(new Action(() => successCount++)); } private void IncreaseFail() { Invoke(new Action(() => failCount++)); } private void ResetStatistics() { totalSend = 0; successCount = 0; failCount = 0; lblStatus.Text = "統計中..."; } private void ShowStatistics() { lblStatus.Text = $"總送出: {totalSend}, 成功: {successCount}, 失敗: {failCount}, 總耗時: {stopwatch.Elapsed.TotalSeconds:F2} 秒"; } } } Form1.Designer.cs(新增 Label) 在最後加: // lblStatus this.lblStatus = new System.Windows.Forms.Label(); this.lblStatus.Location = new System.Drawing.Point(12, 300); this.lblStatus.Size = new System.Drawing.Size(424, 20); this.lblStatus.Text = "統計結果顯示區"; this.Controls.Add(this.lblStatus); // 同時在 Form1 類別中新增一個欄位 private System.Windows.Forms.Label lblStatus; ---------------------------------------------------------------------------- /* SimpleSocketServer.cs 🖥️ 【配套 Server 範例】(Async/await 版) ✅ 支援多 client ✅ 每收到一個訊息就回傳「Server 收到: +原內容」 */ Server 程式 (C# Console) using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; namespace SimpleSocketServer { class Program { static async Task Main(string[] args) { Console.WriteLine("Server 啟動中..."); var listener = new TcpListener(IPAddress.Any, 11000); listener.Start(); while (true) { var client = await listener.AcceptTcpClientAsync(); _ = HandleClientAsync(client); } } private static async Task HandleClientAsync(TcpClient client) { Console.WriteLine($"Client 連線: {client.Client.RemoteEndPoint}"); var stream = client.GetStream(); var buffer = new byte[1024]; try { while (true) { int length = await stream.ReadAsync(buffer, 0, buffer.Length); if (length == 0) break; string message = Encoding.UTF8.GetString(buffer, 0, length); Console.WriteLine($"收到: {message}"); string response = "Server 收到: " + message; byte[] responseBytes = Encoding.UTF8.GetBytes(response); await stream.WriteAsync(responseBytes, 0, responseBytes.Length); } } catch (Exception ex) { Console.WriteLine($"連線錯誤: {ex.Message}"); } finally { Console.WriteLine($"Client 離線: {client.Client.RemoteEndPoint}"); client.Close(); } } } } ✅ 最後小結: 項目 說明 Client WinForm 測試器 支援多 Client 同時連線、每 Client 多次傳送、統計總數、成功失敗、總時間 Server Console 程式 支援多 Client 非同步收發訊息 ------------------------------------- 打包成 zip 做到一半: // MultiClientTesterWinForm (Client) // Program.cs using System; using System.Windows.Forms; namespace MultiClientTesterWinForm { static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } } // Form1.cs using System; using System.Diagnostics; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace MultiClientTesterWinForm { public partial class Form1 : Form { private int totalSend = 0; private int successCount = 0; private int failCount = 0; private Stopwatch stopwatch = new Stopwatch(); public Form1() { InitializeComponent(); } private async void btnStart_Click(object sender, EventArgs e) { string serverIp = txtServerIp.Text.Trim(); int serverPort = int.Parse(txtServerPort.Text.Trim()); int clientCount = int.Parse(txtClientCount.Text.Trim()); int messagePerClient = int.Parse(txtMessagesPerClient.Text.Trim()); listBoxLog.Items.Clear(); ResetStatistics(); stopwatch.Restart(); listBoxLog.Items.Add($"開始啟動 {clientCount} 個 Client,每個傳 {messagePerClient} 次..."); var tasks = new Task[clientCount]; for (int i = 0; i < clientCount; i++) { int clientId = i + 1; tasks[i] = Task.Run(async () => await StartClientAsync(serverIp, serverPort, clientId, messagePerClient)); } await Task.WhenAll(tasks); stopwatch.Stop(); ShowStatistics(); listBoxLog.Items.Add("所有 Client 測試完成!"); } private async Task StartClientAsync(string serverIp, int serverPort, int clientId, int messageCount) { int retry = 0; Socket clientSocket = null; while (retry < 3) { try { clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); await clientSocket.ConnectAsync(new IPEndPoint(IPAddress.Parse(serverIp), serverPort)); AppendLog($"Client {clientId} 已連線"); break; } catch { retry++; AppendLog($"Client {clientId} 第 {retry} 次連線失敗,重試中..."); await Task.Delay(1000); } } if (clientSocket == null || !clientSocket.Connected) { AppendLog($"Client {clientId} 無法連線,放棄。"); IncreaseFail(); return; } try { for (int i = 0; i < messageCount; i++) { string message = $"Client {clientId} 的訊息 {i + 1}"; byte[] messageBytes = Encoding.UTF8.GetBytes(message); await clientSocket.SendAsync(messageBytes, SocketFlags.None); IncreaseTotal(); byte[] buffer = new byte[1024]; int receivedLength = await clientSocket.ReceiveAsync(buffer, SocketFlags.None); string response = Encoding.UTF8.GetString(buffer, 0, receivedLength); AppendLog($"Client {clientId} 收到回應: {response}"); IncreaseSuccess(); await Task.Delay(300); } clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Close(); } catch (Exception ex) { AppendLog($"Client {clientId} 錯誤: {ex.Message}"); IncreaseFail(); } } private void AppendLog(string message) { if (listBoxLog.InvokeRequired) { listBoxLog.Invoke(new Action(AppendLog), message); } else { listBoxLog.Items.Add(message); listBoxLog.TopIndex = listBoxLog.Items.Count - 1; } } private void IncreaseTotal() { Invoke(new Action(() => totalSend++)); } private void IncreaseSuccess() { Invoke(new Action(() => successCount++)); } private void IncreaseFail() { Invoke(new Action(() => failCount++)); } private void ResetStatistics() { totalSend = 0; successCount = 0; failCount = 0; lblStatus.Text = "統計中..."; } private void ShowStatistics() { lblStatus.Text = $"總送出: {totalSend}, 成功: {successCount}, 失敗: {failCount}, 總耗時: {stopwatch.Elapsed.TotalSeconds:F2} 秒"; } } } // Server (SimpleSocketServer) using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; namespace SimpleSocketServer { class Program { static async Task Main(string[] args) { Console.WriteLine("Server 啟動中..."); var listener = new TcpListener(IPAddress.Any, 11000); listener.Start(); while (true) { var client = await listener.AcceptTcpClientAsync(); _ = HandleClientAsync(client); } } private static async Task HandleClientAsync(TcpClient client) { Console.WriteLine($"Client 連線: {client.Client.RemoteEndPoint}"); var stream = client.GetStream(); var buffer = new byte[1024]; try { while (true) { int length = await stream.ReadAsync(buffer, 0, buffer.Length); if (length == 0) break; string message = Encoding.UTF8.GetString(buffer, 0, length); Console.WriteLine($"收到: {message}"); string response = "Server 收到: " + message; byte[] responseBytes = Encoding.UTF8.GetBytes(response); await stream.WriteAsync(responseBytes, 0, responseBytes.Length); } } catch (Exception ex) { Console.WriteLine($"連線錯誤: {ex.Message}"); } finally { Console.WriteLine($"Client 離線: {client.Client.RemoteEndPoint}"); client.Close(); } } } }