【发布时间】:2019-09-10 17:00:45
【问题描述】:
我无法使用取消令牌来停止 TCP 侦听器。第一个代码提取是一个示例,我可以在另一个类的方法中成功停止测试 while 循环。所以我不明白为什么我不能将这种类似的逻辑应用于 TCP 侦听器类。花了很多天阅读有关此主题的令人费解的答案,但找不到合适的解决方案。
我的软件应用程序要求 TCP 侦听器必须让用户能够从服务器端而不是客户端停止它。如果用户想要重新配置此侦听器的端口号,那么他们目前必须关闭软件才能让 Windows 关闭底层套接字,这不好,因为会影响在我的应用程序中运行的其他服务。
第一个代码摘录只是一个示例,我可以在其中停止 while 循环的运行,这可以正常工作,但除了我希望这适用于我的 TCP 侦听器的 faat 之外没有那么相关:
public void Cancel(CancellationToken cancelToken) // EXAMPLE WHICH IS WORKING
{
Task.Run(async () =>
{
while (!cancelToken.IsCancellationRequested)
{
await Task.Delay(500);
log.Info("Test Message!");
}
}, cancelToken);
}
下面是我正在努力解决的实际 TCP 侦听器代码
public void TcpServerIN(string inboundEncodingType, string inboundIpAddress, string inboundLocalPortNumber, CancellationToken cancelToken)
{
TcpListener listener = null;
Task.Run(() =>
{
while (!cancelToken.IsCancellationRequested)
{
try
{
IPAddress localAddr = IPAddress.Parse(inboundIpAddress);
int port = int.Parse(inboundLocalPortNumber);
listener = new TcpListener(localAddr, port);
// Start listening for client requests.
listener.Start();
log.Info("TcpListenerIN listener started");
// Buffer for reading data
Byte[] bytes = new Byte[1024];
String data = null;
// Enter the listening loop.
while (true)
{
// Perform a blocking call to accept client requests.
TcpClient client = listener.AcceptTcpClient();
// Once each client has connected, start a new task with included parameters.
var task = Task.Run(() =>
{
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
data = null;
int i;
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Select Encoding format set by string inboundEncodingType parameter.
if (inboundEncodingType == "UTF8") { data = Encoding.UTF8.GetString(bytes, 0, i); }
if (inboundEncodingType == "ASCII") { data = Encoding.ASCII.GetString(bytes, 0, i); }
// Use this if you want to echo each message directly back to TCP Client
//stream.Write(msg, 0, msg.Length);
// If any TCP Clients are connected then pass the appended string through
// the rules engine for processing, if not don't send.
if ((listConnectedClients != null) && (listConnectedClients.Any()))
{
// Pass the appended message string through the SSSCRulesEngine
SendMessageToAllClients(data);
}
}
// When the remote client disconnetcs, close/release the socket on the TCP Server.
client.Close();
});
}
}
catch (SocketException ex)
{
log.Error(ex);
}
finally
{
// If statement is required to prevent an en exception thrown caused by the user
// entering an invalid IP Address or Port number.
if (listener != null)
{
// Stop listening for new clients.
listener.Stop();
}
}
}
MessageBox.Show("CancellationRequested");
log.Info("TCP Server IN CancellationRequested");
}, cancelToken);
}
【问题讨论】:
-
你有
while(true){ /* block and don’t check cancel token */ }。唯一的出路是通过异常或返回。也许你的内部循环应该检查令牌? -
之前试过了,没什么区别。
-
当
CancellationToken被取消时,您必须关闭侦听器套接字。如果您使用阻塞 API(例如,AcceptTcpClient),那么当CancellationToken被取消时,您需要关闭侦听器套接字从另一个线程。 -
不知道该怎么做,在我的情况下,不同的线程和不同的类。 TCP 侦听器将用于多个实例,因此我需要一种方法来独立关闭每个实例。
标签: tcplistener cancellationtokensource