C# TCP退出Accept阻塞的兩種方法
方法一:將偵聽套接字強行關掉,這樣會使Accept引發異常,從而達到退出阻塞的目的。方法二:先拆除循環條件,再給監聽端口發送一條自定義命令,解析成功后,Accept自然退出阻塞。
后臺代碼:
using System;using System.Text;using System.Windows;using System.Threading;using System.Net;using System.Net.Sockets;namespace SocketBlockingInterrupt{ public partial class MainWindow : Window { bool bIsExecute; TcpListener listener;//監聽套接字 SynchronizationContext synContext; public MainWindow() { InitializeComponent(); synContext = SynchronizationContext.Current; btnStop.IsEnabled = false; } PRivate void btnStart_Click(object sender, RoutedEventArgs e) { bIsExecute = true; //建立循環條件 btnStart.IsEnabled = false; btnStop.IsEnabled = true; //開啟監聽線程 Thread t = new Thread(new ThreadStart(ListenThread)); t.IsBackground = true; t.Start(); } void ListenThread() { ipEndPoint localEP = new IPEndPoint(IPAddress.Any, 9000); listener = new TcpListener(localEP); listener.Start(); //啟動監聽,非阻塞 synContext.Post(updateUI, "監聽線程:正在監聽中..."); while (bIsExecute) //循環條件 { byte[] recvBuff = new byte[512]; //捕獲異常,強行退出Accept阻塞 try { synContext.Post(updateUI, "監聽線程:Accept正在阻塞中..."); TcpClient client = listener.AcceptTcpClient(); // 等待連接(阻塞) synContext.Post(updateUI, "監聽線程:收到連接請求,已退出Accept阻塞"); int recvByte = client.Client.Receive(recvBuff);// 建立連接 // 解析命令 byte[] buff = new byte[recvByte]; for (int i = 0; i < recvByte; i++ ) { buff[i] = recvBuff[i]; } string exitByt = Encoding.ASCII.GetString(buff); if (exitByt == "Exit") { synContext.Post(updateUI, "監聽線程:收到數據" + exitByt); break; } } catch (SocketException ex) { synContext.Post(updateUI, "監聽線程:發生異常,Accept阻塞被強行退出:" + ex.Message); break; } } synContext.Post(updateUI, "監聽線程:已成功退出監聽"); } private void btnStop_Click(object sender, RoutedEventArgs e) { bIsExecute = false; //此處拆除循環條件 //方法1:直接停止監聽套接字,引發異常從而強行使Accept退出阻塞。 //--------------------------------------------- //if (listener != null) //{ // listener.Stop(); //} //--------------------------------------------- //方法2:主動發送一條數據,使Accept自然地退出阻塞。 //--------------------------------------------- TcpClient tcpClient = new TcpClient(); tcpClient.Connect("127.0.0.1",9000); NetworkStream ns = tcpClient.GetStream(); if (ns.CanWrite) { Byte[] sendBytes = Encoding.ASCII.GetBytes("Exit"); ns.Write(sendBytes, 0, sendBytes.Length); lbMsg.Items.Add("發送退出命令成功!"); } else { lbMsg.Items.Add("發送退出命令失敗!"); return; } ns.Close(); tcpClient.Close(); //--------------------------------------------- btnStart.IsEnabled = true; btnStop.IsEnabled = false; } void updateUI(object o) { string str = (string)o; lbMsg.Items.Add(str); } }}WPF前臺代碼:
<Window x:Class="SocketBlockingInterrupt.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> <Button Content="開始偵聽" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="btnStart" VerticalAlignment="Top" Width="75" Click="btnStart_Click" /> <Button Content="結束偵聽" Height="23" HorizontalAlignment="Left" Margin="108,12,0,0" Name="btnStop" VerticalAlignment="Top" Width="75" Click="btnStop_Click" /> <ListBox Height="258" HorizontalAlignment="Left" Margin="12,41,0,0" Name="lbMsg" VerticalAlignment="Top" Width="479" /> </Grid></Window>
新聞熱點
疑難解答