傳統阻塞式 Accept() 會凍結主執行緒,導致 UI 無回應。.NET Socket 類別內建非同步模式(APM),透過 BeginAccept/EndAccept、BeginReceive/EndReceive 等配對方法,搭配回呼函式,即可在不阻塞主執行緒的情況下處理高併發連線。
listener.BeginAccept(OnConnectRequest, listener)OnConnectRequest 中呼叫 listener.EndAccept() 取得 client socket,並立即 listener.BeginAccept(...) 繼續監聽下一個連線client.BeginReceive(OnReceivedData, client)OnReceivedData 中 EndReceive() 解析封包,處理完畢後再次 BeginReceive() 形成循環const int nPortListen = 399;
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(new IPEndPoint(aryLocalAddr[0], nPortListen));
listener.Listen(10);
listener.BeginAccept(new AsyncCallback(OnConnectRequest), listener);
public void OnConnectRequest(IAsyncResult ar) {
Socket listener = (Socket)ar.AsyncState;
Socket client = listener.EndAccept(ar);
Console.WriteLine("Client {0} joined", client.RemoteEndPoint);
// 送出歡迎訊息
byte[] data = Encoding.ASCII.GetBytes("Welcome " + DateTime.Now + "\r\n");
client.Send(data, data.Length, 0);
// 繼續監聽下一個連線
listener.BeginAccept(new AsyncCallback(OnConnectRequest), listener);
}
public void Connect(string serverAdd, int port) {
clientSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientSock.Blocking = false;
IPEndPoint ep = new IPEndPoint(IPAddress.Parse(serverAdd), port);
clientSock.BeginConnect(ep, new AsyncCallback(OnConnect), clientSock);
}
public void OnConnect(IAsyncResult ar) {
Socket sock = (Socket)ar.AsyncState;
if (sock.Connected) {
sock.BeginReceive(msgBuff, 0, msgBuff.Length, SocketFlags.None,
new AsyncCallback(OnReceivedData), sock);
}
}
public void OnReceivedData(IAsyncResult ar) {
Socket sock = (Socket)ar.AsyncState;
try {
int nBytes = sock.EndReceive(ar);
if (nBytes > 0) {
string msg = Encoding.ASCII.GetString(msgBuff, 0, nBytes);
ParseMessage(sock, msg);
SetupReceiveCallback(sock); // 重新掛接接收
} else {
sock.Shutdown(SocketShutdown.Both); sock.Close();
}
} catch { /* 錯誤處理 */ }
}

非同步 Socket 事件觸發流程:BeginAccept → OnConnectRequest → BeginReceive → OnReceivedData → 再次 BeginReceive
範例實作一個簡易 P2P 節點:每個節點同時具備伺服端(start 400)與客戶端(connect ip port)功能,支援 get x y/set x y val 操作共享二維陣列。完整代碼可參考附件。
.NET 非同步 Socket 透過 APM 模式將複雜的多執行緒同步問題轉化為事件回呼,大幅降低開發難度。掌握「啟動非同步操作 → 回呼中結束操作 → 立即發起下一個非同步操作」的循環模式,即可構建高效能網路服務。