本實例展示 即時應用 架構:客戶端 (TcpClient) 與伺服器 (TcpServer) 透過 Socket 類別進行即時雙向通訊,並示範 ListView 控件在多執行緒環境下的安全更新、XML 格式資料傳輸。
WaitingForClient) 接受連線,每連線建立專屬執行緒 (ReadSocket) 處理通訊,Socket 實例存於 Hashtable socketHolder,執行緒存於 threadHolder。StartReceive) 讀取 Socket 資料,透過 MethodInvoker / BeginInvoke 安全更新 UI ListView。Hashtable socketHolder = new Hashtable();
Hashtable threadHolder = new Hashtable();
public Form1() {
InitializeComponent();
tcpLsn = new TcpListener(8002);
tcpLsn.Start();
stpanel.Text = "Listen at: " + tcpLsn.LocalEndpoint.ToString();
Thread tcpThd = new Thread(new ThreadStart(WaitingForClient));
threadHolder.Add(connectId, tcpThd);
tcpThd.Start();
}
private void menuConn_Click(object sender, EventArgs e) {
ConnectDlg dlg = new ConnectDlg();
if (dlg.ShowDialog(this) == DialogResult.OK) {
s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress host = IPAddress.Parse(dlg.IpAdd);
int port = Int32.Parse(dlg.PortNum);
IPEndPoint ep = new IPEndPoint(host, port);
try {
s.Connect(ep);
if (s.Connected) {
byte[] buf = ASCII.GetBytes(String.Format("{0}:{1}", dlg.UserName, dlg.PassWord));
s.Send(buf, 0, buf.Length, 0); // 發送驗證封包
t = new Thread(new ThreadStart(StartReceive));
t.Start();
sbar.Text = "Ready to receive data";
}
} catch (Exception ex) { MessageBox.Show(ex.ToString()); }
}
}
private void StartReceive() {
miv = new MethodInvoker(this.UpdateListView);
int cnt = 0; string tmp = null; byte[] firstb = new byte[1];
while (true) {
try {
byte[] receive = new byte[1];
int ret = s.Receive(receive, 1, 0); // 逐位元組接收
if (ret > 0) {
switch (receive[0]) {
case 11: cnt = 0; break; // VT 起始碼
case 10: // LF 結束碼
cnt = 0;
if (firstb[0] == ':') HandleCommand(tmp);
else if (firstb[0] == '<') HandleXML(tmp);
else HandleText(tmp);
tmp = null; break;
default:
if (cnt == 0) firstb[0] = receive[0];
tmp += Encoding.ASCII.GetString(receive);
cnt++; break;
}
}
} catch (Exception ex) { if (!s.Connected) break; }
}
t.Abort();
}
協議設計:以 VT (0x0B) 為訊息起始、LF (0x0A) 為結束;首位元組判斷類型(: 指令、< XML、其他純文字),分派對應處理函數。
WaitingForClient 迴圈持續 AcceptSocket,建立連線 ID、儲存 Socket/執行緒至 HashTable、啟動 ReadSocket 執行緒,並在 UI ListView 顯示連線資訊。此為經典「一連線一執行緒」模型,適合中小規模即時應用。