在前一篇文章中我們使用了基礎的 Socket 類別,實際上 System.Net.Sockets 命名空間還提供了更高層級的抽象類別:TcpClient、UdpClient 以及用於資料流處理的 NetworkStream。這些類別大幅簡化了網路程式的開發複雜度。
TcpClient tcpClient = new TcpClient("伺服器IP", 連接埠號);
NetworkStream ns = tcpClient.GetStream();
TcpListener tcpListener = new TcpListener(監聽連接埠);
tcpListener.Start();
TcpClient tcpClient = tcpListener.AcceptTcpClient();
NetworkStream ns = tcpClient.GetStream();
伺服器端使用 TcpListener 監聽連線請求,接受連線後將其封裝為 TcpClient 物件,再透過 GetStream() 取得 NetworkStream 進行資料收發。
UdpClient 的使用方式更為直接,實例化後即可呼叫 Send 和 Receive 方法。需注意:UDP 無連線特性,UdpClient 不提供 GetStream 方法,因此無法使用資料流方式操作;且 UDP 通訊不需要伺服器端監聽機制。
理解基本流程後,我們來實作一個稍微複雜的廣播式聊天程式。
ListBox:顯示聊天訊息TextBox:輸入發言內容點擊「連線」後彈出對話框,輸入伺服器 IP、連接埠與暱稱,啟動接收執行緒負責監聽伺服器訊息並更新 ListBox。
ListBox:顯示已連線用戶的 IP 與連接埠傳送前以 UTF-8 編碼,接收端還原為 GB2312,否則中文會顯示亂碼。
.NET 2.0 中,非 UI 執行緒直接修改視窗控制項屬性會拋出例外。解決方案是定義委派,透過 Invoke 方式安全更新介面。
客戶端關閉視窗時(FormClosing 事件),發送特定「Close」指令給伺服器。伺服器輪詢偵測到以「Close」開頭的訊息,即斷開該用戶連線。為避免衝突,正常聊天訊息會加上 IP 與暱稱前綴,不會誤觸發斷線邏輯。