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

Windows 8 市集應用程式開發實戰 (62):Socket 通訊 - TCP 與 UDP 實作

     編輯:關於.NET

前言:重新想像 Windows 8 通訊機制

Windows 8 市集應用程式(Windows Store Apps)提供豐富的網路通訊 API,其中 Windows.Networking.Sockets 命名空間支援 TCP 與 UDP 兩種傳輸協定,讓開發者能建立即時通訊、自訂協定伺服器或輕量級資料傳輸應用。本文透過三個完整範例,示範如何在同一個應用程式中同時扮演伺服器與用戶端角色,實作 TCP 通訊、自訂 HTTP 伺服器與 UDP 資料傳遞。

範例一:TCP Socket 雙向通訊

核心類別與權限宣告

  • StreamSocketListener:TCP 伺服器端監聽器
  • StreamSocket:TCP 用戶端連線
  • DataWriter / DataReader:資料序列化與反序列化
  • 需在 Package.appxmanifest 加入 <Capability Name="privateNetworkClientServer" />

介面設計 (TcpDemo.xaml)

簡單的 StackPanel 佈局,包含四個按鈕(啟動監聽、連線伺服器、發送資料、關閉連線)與一個 TextBlock 顯示訊息記錄。

核心邏輯 (TcpDemo.xaml.cs)

1. 啟動 TCP 監聽器

private async void btnStartListener_Click(object sender, RoutedEventArgs e) {
    _listener = new StreamSocketListener();
    _listener.ConnectionReceived += _listener_ConnectionReceived;
    try {
        await _listener.BindServiceNameAsync("2211");
        lblMsg.Text += "已在本機 2211 埠啟動 TCP 監聽" + Environment.NewLine;
    } catch (Exception ex) {
        // 錯誤處理:取得 SocketErrorStatus 並顯示
    }
}

2. 處理連入連線與資料接收

採用自訂協定:前 4 位元組為無號整數標示資料長度,後續為字串內容。使用 DataReader.LoadAsync 非同步讀取標頭與本體,並在 UI 執行緒更新介面。

async void _listener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args) {
    DataReader reader = new DataReader(args.Socket.InputStream);
    // 更新 UI 顯示遠端端點資訊
    try {
        while (true) {
            uint sizeFieldCount = await reader.LoadAsync(sizeof(uint));
            if (sizeFieldCount != sizeof(uint)) return;
            uint stringLength = reader.ReadUInt32();
            uint actualStringLength = await reader.LoadAsync(stringLength);
            if (stringLength != actualStringLength) return;
            await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => {
                lblMsg.Text += "接收到資料: " + reader.ReadString(actualStringLength) + Environment.NewLine;
            });
        }
    } catch (Exception ex) { /* 錯誤處理 */ }
}

3. 用戶端連線與發送資料

private async void btnConnectListener_Click(object sender, RoutedEventArgs e) {
    _client = new StreamSocket();
    await _client.ConnectAsync(new HostName("127.0.0.1"), "2211");
    lblMsg.Text += "已連線至 127.0.0.1:2211" + Environment.NewLine;
}

private async void btnSendData_Click(object sender, RoutedEventArgs e) {
    if (_writer == null) _writer = new DataWriter(_client.OutputStream);
    string data = "hello webabcd " + DateTime.Now.ToString("HH:mm:ss");
    _writer.WriteUInt32(_writer.MeasureString(data)); // 寫入長度標頭
    _writer.WriteString(data); // 寫入本體
    await _writer.StoreAsync();
    lblMsg.Text += "資料已發送: " + data + Environment.NewLine;
}

4. 正確關閉連線

呼叫 DetachStream() 解除 DataWriter 與 Stream 關聯,再依序 Dispose 用戶端、伺服器物件。

範例二:自訂 HTTP 伺服器 (僅限應用程式內部呼叫)

架構說明

同樣使用 StreamSocketListener 監聽埠 2212,但在 ConnectionReceived 事件中手動解析 HTTP 請求標頭(讀取至 \r\n\r\n),並組裝符合 HTTP/1.1 規範的回應(狀態碼、標頭、內容長度、本體)。

關鍵程式碼片段

async void _listener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args) {
    DataReader reader = new DataReader(args.Socket.InputStream);
    StringBuilder sb = new StringBuilder();
    while (true) {
        uint loaded = await reader.LoadAsync(1);
        if (loaded != 1) return;
        char c = (char)reader.ReadByte();
        sb.Append(c);
        if (sb.ToString().IndexOf("\r\n\r\n") > 0) {
            // 解析完成,組裝回應
            string response = "HTTP/1.1 200 OK\r\nContent-Type:text/html\r\nServer:Custom Http Server\r\nContent-Length:2\r\nConnection: Keep-Alive\r\n\r\nok";
            DataWriter writer = new DataWriter(args.Socket.OutputStream);
            writer.WriteString(response);
            await writer.StoreAsync();
            sb.Clear();
        }
    }
}

用戶端使用 HttpClient.GetStringAsync 呼叫 https://localhost:2212/abc.html 驗證伺服器運作。

範例三:UDP Datagram 通訊

核心差異

  • 使用 DatagramSocket 取代 StreamSocket
  • 無連線概念,ConnectAsync 僅設定預設發送目標
  • 資料單位為 Datagram,最大 65,535 位元組(含標頭)
  • 事件為 MessageReceived,透過 DatagramSocketMessageReceivedEventArgs.GetDataReader() 取得資料

發送端邏輯

private async void btnSendData_Click(object sender, RoutedEventArgs e) {
    if (_client == null) {
        _client = new DatagramSocket();
        await _client.ConnectAsync(new HostName("127.0.0.1"), "2213");
    }
    if (_writer == null) _writer = new DataWriter(_client.OutputStream);
    string data = "hello webabcd " + DateTime.Now.ToString("HH:mm:ss");
    _writer.WriteString(data);
    await _writer.StoreAsync();
    lblMsg.Text += "資料已發送: " + data + Environment.NewLine;
}

接收端處理

private void _listener_MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args) {
    DataReader dataReader = args.GetDataReader();
    uint stringLength = dataReader.UnconsumedBufferLength;
    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => {
        lblMsg.Text += "接收到資料: " + dataReader.ReadString(stringLength) 
            + " - 來源: " + args.RemoteAddress.RawName + ":" + args.RemotePort + Environment.NewLine;
    });
}

總結與原始碼下載

三個範例完整展示 Windows 8 市集應用程式中 Socket 程式設計的核心模式:TCP 可靠串流、自訂應用層協定(HTTP)、UDP 無連線資料報。開發者可根據即時性、可靠性與負載需求選擇適當方案。

完整原始碼下載: https://files.cnblogs.com/webabcd/Windows8.rar

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