Windows 8 (WinRT) 與 UWP 應用通過 Windows.Networking.Sockets.StreamSocket 進行 TCP 通訊。本文提供一個完整的「WinForms 桌面服務端 + UWP 客戶端」示例,重點解決 DataReader 讀取長度前綴消息的常見陷阱,實現可靠的字串/二進制數據雙向傳輸。
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TestServerApp
{
public partial class Form1 : Form
{
private TcpListener _listener;
private TcpClient _client;
public Form1()
{
InitializeComponent();
btnStart.Enabled = true;
btnStop.Enabled = false;
}
private void SendMessage(TcpClient client)
{
using (var stream = client.GetStream())
{
string msg = "奔,不停地奔,奔向傳說中的荒原;飛,不停地飛,飛向天空的那一端。";
byte[] buffer = Encoding.UTF8.GetBytes(msg);
uint len = (uint)buffer.Length;
// 先發送 4 字節長度 (大端序/網絡序)
stream.Write(BitConverter.GetBytes(len), 0, sizeof(uint));
// 再發送數據
stream.Write(buffer, 0, buffer.Length);
}
}
private async void btnStart_Click(object sender, EventArgs e)
{
if (_listener == null)
_listener = new TcpListener(IPAddress.Parse(txtAddr.Text), (int)udPort.Value);
_listener.Start();
lblMsg.Text = "監聽已開始。";
btnStart.Enabled = false;
btnStop.Enabled = true;
try
{
_client = await _listener.AcceptTcpClientAsync();
SendMessage(_client);
}
catch (SocketException se) { lblMsg.Text = se.Message; }
catch (Exception ex) { lblMsg.Text = ex.Message; }
}
private void btnStop_Click(object sender, EventArgs e)
{
_listener?.Stop();
lblMsg.Text = "監聽已停止。";
btnStart.Enabled = true;
btnStop.Enabled = false;
}
}
}
雙擊 `Package.appxmanifest` → **功能** 選項卡 → 勾選:

<Page
x:Class="WCleintApp.MainPage"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Margin="3">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Text="服務器:"/>
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Text="端口:"/>
<TextBox x:Name="txtServer" Grid.Row="0" Grid.Column="1" Margin="2,3"/>
<TextBox x:Name="txtPort" Grid.Row="1" Grid.Column="1" Margin="2,3"/>
</Grid>
<StackPanel Grid.Row="1" Margin="5">
<Button Content="連接" Click="onConnClick" Margin="3,8,0,12" Padding="4,2.5"/>
<TextBox x:Name="txtRec" Margin="5,7,0,0" Height="200" IsReadOnly="True"/>
</StackPanel>
</Grid>
</Page>
using System;
using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace WCleintApp
{
public sealed partial class MainPage : Page
{
private StreamSocket _socket;
private DataReader _reader;
public MainPage()
{
this.InitializeComponent();
}
private async void onConnClick(object sender, RoutedEventArgs e)
{
if (_socket != null)
{
_socket.Dispose();
_reader?.DetachStream();
}
_socket = new StreamSocket();
_reader = new DataReader(_socket.InputStream);
// 關鍵:設定 Unicode 編碼 (UTF-8) 與位元組序 (小端序/大端序需與發送端一致)
_reader.UnicodeEncoding = UnicodeEncoding.Utf8;
_reader.ByteOrder = ByteOrder.BigEndian; // 網絡序為大端序
try
{
HostName host = new HostName(txtServer.Text);
string port = txtPort.Text;
await _socket.ConnectAsync(host, port);
txtRec.Text = "連接成功,正在接收數據...";
// 1. 讀取長度前綴 (4 字節 uint)
uint len = await _reader.LoadAsync(sizeof(uint));
if (len != sizeof(uint)) { txtRec.Text = "讀取長度失敗"; return; }
uint dataLength = _reader.ReadUInt32();
// 2. 讀取實際數據
uint loaded = await _reader.LoadAsync(dataLength);
if (loaded != dataLength) { txtRec.Text = "數據不完整"; return; }
string received = _reader.ReadString(dataLength);
txtRec.Text = received;
}
catch (Exception ex)
{
txtRec.Text = "錯誤: " + ex.Message;
}
}
}
}
| 問題 | 原因 | 解決 |
|---|---|---|
| DataReader 讀不到數據 / 讀到亂碼 | 未正確設定 UnicodeEncoding 與 ByteOrder,或未先 LoadAsync 再 ReadXxx | 設定 _reader.UnicodeEncoding = UnicodeEncoding.Utf8; _reader.ByteOrder = ByteOrder.BigEndian; (與發送端 BitConverter.GetBytes 預設小端序不同,需雙方協商一致),嚴格遵循 await LoadAsync(n) 後再 ReadXxx |
| 連接超時 / 拒絕 | 防火牆阻擋、IP/端口錯誤、服務端未啟動 | 檢查 Windows 防火牆入站規則、確認服務端 IP (本機用 127.0.0.1)、端口一致 |
| 發送中文亂碼 | 編碼不一致 | 雙方統一 UTF-8:服務端 Encoding.UTF8.GetBytes,客戶端 UnicodeEncoding.Utf8 |
| 大數據傳輸卡死 | 未分片發送/接收,緩衝區滿 | 應用層協議設計:長度前綴 + 分片循環 LoadAsync/ReadBytes,或使用 StreamSocketListener 服務端模式 |
DataWriter writer = new DataWriter(_socket.OutputStream); writer.WriteUInt32((uint)buffer.Length); writer.WriteBytes(buffer); await writer.StoreAsync(); writer.DetachStream();NetworkStream 循環 Read 長度再讀數據。WinRT/UWP StreamSocket + DataReader/DataWriter 提供了現代異步 TCP 程式設計模型,關鍵在於:**協議設計 (長度前綴)、編碼統一 (UTF-8)、位元組序協商 (BigEndian)、嚴格的 LoadAsync/Read 配對**。掌握這些細節,即可構建穩定高效的跨平台 (桌面/手機/IoT) 網絡應用。