Socket 類型詳細對照
| 常數 | 協定 | 可靠性 | 資料單位 | 典型應用 |
| SOCK_STREAM | TCP | 可靠、有序、無重複 | 位元組流 | Web、郵件、檔案傳輸 |
| SOCK_DGRAM | UDP | 不可靠、可能亂序/重複 | 資料報 | DNS、串流、即時通訊 |
| SOCK_RAW | IP/ICMP | 原始封包 | IP 封包 | ping、路由追蹤 |
同步 TCP 伺服端完整實作
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
public partial class ServerForm : Form {
private Thread _listenThread;
private Socket _serverSocket;
protected override void Dispose(bool disposing) {
try {
_serverSocket?.Close();
_listenThread?.Abort();
} catch { }
base.Dispose(disposing);
}
private static IPAddress GetLocalIP() {
var host = Dns.GetHostEntry(Dns.GetHostName());
return host.AddressList.First(ip => ip.AddressFamily == AddressFamily.InterNetwork);
}
private void ListenLoop() {
var ep = new IPEndPoint(GetLocalIP(), 8000);
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_serverSocket.Bind(ep);
_serverSocket.Listen(5);
byte[] buffer = new byte[1024];
while (true) {
try {
var client = _serverSocket.Accept(); // 阻塞等待連線
int recv = client.Receive(buffer);
string msg = $"{DateTime.Now:T}: {client.RemoteEndPoint} -> {Encoding.UTF8.GetString(buffer, 0, recv)}";
Invoke(() => lstMessages.Items.Add(msg)); // 跨執行緒更新 UI
client.Close();
} catch (SocketException ex) {
Invoke(() => lblStatus.Text = ex.Message);
}
}
}
private void btnStart_Click(object sender, EventArgs e) {
try {
_listenThread = new Thread(ListenLoop) { IsBackground = true };
_listenThread.Start();
lblStatus.Text = "Listening...";
} catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}
}
關鍵架構決策
| 決策點 | 同步阻塞模式 | 非同步/IOCP 模式 |
| 併發能力 | 單一執行緒串行處理 | 單執行緒處理萬級連線 |
| 程式複雜度 | 低 | 高(APM/EAP/TAP) |
| 適用場景 | 內部工具、低負載、教學 | 高併發伺服器、即時系統 |
| 資源佔用 | 每連線一執行緒(若多執行緒版) | 少量執行緒池 |
多執行緒版伺服端(每連線一執行緒)
private void ListenLoop() {
// ... Bind/Listen 同上 ...
while (true) {
var client = _serverSocket.Accept();
ThreadPool.QueueUserWorkItem(HandleClient, client);
}
}
private void HandleClient(object state) {
var client = (Socket)state;
try {
byte[] buffer = new byte[1024];
int recv = client.Receive(buffer);
string msg = $"{DateTime.Now:T}: {client.RemoteEndPoint} -> {Encoding.UTF8.GetString(buffer, 0, recv)}";
Invoke(() => lstMessages.Items.Add(msg));
} catch (Exception ex) {
Invoke(() => lstMessages.Items.Add($"Error: {ex.Message}"));
} finally {
client.Close();
}
}
UI 執行緒安全:Invoke/BeginInvoke
- WinForms 控制項只能在建立它們的執行緒存取
Control.Invoke(delegate):同步封送至 UI 執行緒
Control.BeginInvoke(delegate):非同步佇列,不阻塞工作執行緒
- .NET Core / .NET 5+ 建議用
SynchronizationContext 或 Dispatcher
資源清理檢查清單
Socket.Close() / Dispose() 釋放非託管控制代碼
Thread.Abort() 停止監聽迴圈(或用 CancellationToken 優雅退出)
Form.Dispose 中集中清理
- 設定
IsBackground = true 避免阻塞進程退出
效能調優提示
- 接收緩衝區大小:
Socket.ReceiveBufferSize(預設 8KB,高吞吐可調大)
- Nagle 演算法:
Socket.NoDelay = true 關閉,減少小封包延遲
- 非同步 I/O:
SocketAsyncEventArgs / ValueTask 避免分配
- 連線池/物件池:重用
SocketAsyncEventArgs、緩衝區