首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 簡易 Socket 通訊範例:主控台伺服器與 WinForms 用戶端

     編輯:關於C語言

前言

本文提供最精簡的 TCP Socket 通訊範例:主控台應用程式作為回聲伺服器 (收到訊息轉大寫並回傳),WinForms 應用程式作為用戶端,透過文字方塊輸入、列表方塊顯示收發紀錄。適合初學者理解 TcpListener/TcpClient、NetworkStream、StreamReader/Writer 基礎運作。

伺服器端 (主控台應用程式)

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;

public class EchoServer
{
    public static void Main()
    {
        const int Port = 1234;
        IPAddress ip = IPAddress.Parse("127.0.0.1"); // 僅本機測試
        // IPAddress ip = IPAddress.Any; // 監聽所有介面

        TcpListener listener = new TcpListener(ip, Port);
        listener.Start();
        Console.WriteLine($"Server started on {ip}:{Port}. Waiting for client...");

        // 同步阻塞等待單一用戶端 (示範用,實務應用循環 Accept 或非同步)
        using (Socket clientSocket = listener.AcceptSocket())
        {
            Console.WriteLine($"Client connected: {clientSocket.RemoteEndPoint}");

            using (NetworkStream ns = new NetworkStream(clientSocket))
            using (StreamReader reader = new StreamReader(ns))
            using (StreamWriter writer = new StreamWriter(ns) { AutoFlush = true })
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    Console.WriteLine($"Received: {line}");
                    string reply = line.ToUpper() + "!";
                    writer.WriteLine(reply);
                    Console.WriteLine($"Sent: {reply}");
                }
            }
        }
        Console.WriteLine("Client disconnected. Press any key to exit.");
        Console.ReadKey();
    }
}

用戶端端 (WinForms 應用程式)

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Net.Sockets;
using System.Windows.Forms;

public class ClientForm : Form
{
    private TextBox txtInput;
    private Button btnSend;
    private ListBox lstMessages;
    private TcpClient _client;
    private StreamReader _reader;
    private StreamWriter _writer;
    private readonly List _messageLog = new List();

    public ClientForm()
    {
        InitializeComponent();
        ConnectToServer();
    }

    private void InitializeComponent()
    {
        this.Text = "Socket Client Demo";
        this.Size = new Size(450, 350);
        this.StartPosition = FormStartPosition.CenterScreen;

        txtInput = new TextBox { Left = 20, Top = 20, Width = 300, Height = 25 };
        txtInput.TextChanged += (s, e) => btnSend.Enabled = txtInput.TextLength > 0;

        btnSend = new Button { Text = "Send", Left = 330, Top = 20, Width = 80, Height = 25, Enabled = false };
        btnSend.Click += BtnSend_Click;

        lstMessages = new ListBox { Left = 20, Top = 60, Width = 390, Height = 230, Font = new Font("Consolas", 9) };

        this.Controls.AddRange(new Control[] { txtInput, btnSend, lstMessages });
    }

    private void ConnectToServer()
    {
        try
        {
            _messageLog.Add("Connecting to 127.0.0.1:1234...");
            _client = new TcpClient("127.0.0.1", 1234);
            _messageLog.Add("Connected. Type message and click Send.");

            NetworkStream ns = _client.GetStream();
            _reader = new StreamReader(ns);
            _writer = new StreamWriter(ns) { AutoFlush = true };

            RefreshLog();
        }
        catch (Exception ex)
        {
            _messageLog.Add($"Connection failed: {ex.Message}");
            RefreshLog();
        }
    }

    private void BtnSend_Click(object sender, EventArgs e)
    {
        if (string.IsNullOrWhiteSpace(txtInput.Text)) return;

        try
        {
            string msg = txtInput.Text.Trim();
            _writer.WriteLine(msg);
            _messageLog.Add($">> {msg}");

            string reply = _reader.ReadLine();
            _messageLog.Add($"<< {reply}");

            txtInput.Clear();
            txtInput.Focus();
        }
        catch (Exception ex)
        {
            _messageLog.Add($"Error: {ex.Message}");
        }
        finally
        {
            RefreshLog();
        }
    }

    private void RefreshLog()
    {
        lstMessages.Items.Clear();
        lstMessages.Items.AddRange(_messageLog.ToArray());
        lstMessages.TopIndex = lstMessages.Items.Count - 1; // 自動捲動到底
    }

    protected override void OnFormClosing(FormClosingEventArgs e)
    {
        _writer?.WriteLine("BYE");
        _writer?.Flush();
        _reader?.Close();
        _writer?.Close();
        _client?.Close();
        base.OnFormClosing(e);
    }

    [STAThread]
    public static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new ClientForm());
    }
}

執行步驟與驗證

  1. 建立兩個專案:Console App (Server) 與 Windows Forms App (Client)。
  2. 將上述程式碼分別貼入 Program.cs (Server) 與 Form1.cs (Client,改類別名為 ClientForm 並更新 Main)。
  3. 先啟動 Server 專案,主控台顯示 Server started...。
  4. 再啟動 Client 專案,視窗出現,列表方塊顯示 Connected.。
  5. 在文字方塊輸入 hello world,點擊 Send,列表顯示:
    > hello world
    < HELLO WORLD!

核心類別關係圖

TcpListener (Server)
    └─ AcceptSocket() → Socket
TcpClient (Client)
    └─ GetStream() → NetworkStream
NetworkStream (雙向串流)
    ├─ StreamReader  → ReadLine() (文字行讀取)
    └─ StreamWriter  → WriteLine() (文字行寫入,AutoFlush=true 即時送出)

常見問題與解決

現象原因解決
用戶端連不上防火牆阻擋、IP/Port 錯誤、伺服器未啟動檢查防火牆規則,確認 IP (127.0.0.1 vs 實體 IP)、Port 一致
ReadLine 卡住不回傳對方未送出換行符 \r\n、串流未 Flush確雙方皆用 WriteLine/ReadLine,Writer 設 AutoFlush=true
中文亂碼編碼不一致指定編碼:new StreamReader(ns, Encoding.UTF8), new StreamWriter(ns, Encoding.UTF8)
只能單一用戶端Server 只 Accept 一次放入 while 迴圈或改用非同步 AcceptAsync / ThreadPool

進階擴充方向

  • 多用戶端支援:Server 端 while(true) { Socket s = listener.AcceptSocket(); ThreadPool.QueueUserWorkItem(HandleClient, s); }
  • 非同步 I/O:ReadLineAsync/WriteLineAsync 搭配 await,避免阻塞執行緒。
  • 訊息框架:定義長度前綴 (4 bytes) + JSON/Protobuf 本體,解決 TCP 黏包/拆包。
  • 加密傳輸:使用 SslStream 替代 NetworkStream。
  • 心跳機制:定期送出 PING 偵測斷線。

結語

此範例展示 .NET 核心網路類別 TcpListener/TcpClient 搭配串流讀寫器的最基本用法。掌握同步阻塞模型後,建議直接進入 async/await 非同步模式與訊息協定設計,才是實務專案的標準開發路徑。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved