C# TCP退出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>