Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 关于重置事件和线程,此tcp侦听器代码是否正确实现?_C#_Multithreading_Tcp_Windows Services - Fatal编程技术网

C# 关于重置事件和线程,此tcp侦听器代码是否正确实现?

C# 关于重置事件和线程,此tcp侦听器代码是否正确实现?,c#,multithreading,tcp,windows-services,C#,Multithreading,Tcp,Windows Services,我有这个代码,我觉得它工作得不好。我已经把它拼凑在一起,它可以工作,但我不完全理解异步线程和ResetEvents 当我用一个多线程客户端测试这个监听器时,响应时间从最初10秒左右的300毫秒到最后50秒的2-3秒 1.)线程和resetevent处理程序是否按照设计的方式实现 2.)是否有办法加快高流量突发的响应时间 3.)在另一个线程上运行tcpConnectionLogic有意义吗 我有一个全局范围的手动和自动重置事件: private AutoResetEvent connecti

我有这个代码,我觉得它工作得不好。我已经把它拼凑在一起,它可以工作,但我不完全理解异步线程和ResetEvents

当我用一个多线程客户端测试这个监听器时,响应时间从最初10秒左右的300毫秒到最后50秒的2-3秒

1.)线程和resetevent处理程序是否按照设计的方式实现

2.)是否有办法加快高流量突发的响应时间

3.)在另一个线程上运行tcpConnectionLogic有意义吗

我有一个全局范围的手动和自动重置事件:

   private AutoResetEvent connectionWaitHandle = new AutoResetEvent(false);
   private ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
我有一个windows服务,它在新线程上启动tcp侦听器

protected override void OnStart(string[] args)
{
    _mainThread = new Thread(ThreadListener_Begin);

    _mainThread.Name = "EMServiceThread";
    _mainThread.IsBackground = false;
    _mainThread.Start();
}
我的线程运行一个循环,等待手动重新发送事件发出关机信号

private void ThreadListener_Begin()
{
    TcpListener listener = null;
    listener = new TcpListener(IPAddress.Parse("172.16.30.248"), 10010);

    listener.ExclusiveAddressUse = false;
    listener.Start();

        while (!_shutdownEvent.WaitOne(0))
        {
            IAsyncResult result = listener.BeginAcceptTcpClient(HandleAsyncConnection, listener);
            connectionWaitHandle.WaitOne();
        }
}
最后,当连接进来时,我接受它并将其传递给一种逻辑层,该逻辑层处理请求

private void HandleAsyncConnection(IAsyncResult result)
{ 
  TcpListener listener = (TcpListener)result.AsyncState;

  connectionWaitHandle.Set();

  TcpClient c = listener.EndAcceptTcpClient(result);

  var _tcpConnectedLogic = new TcpConnectionLogic(c);

  _tcpConnectedLogic.BadRequestAlert += _serviceLogic_BadRequestAlert;
  _tcpConnectedLogic.RequestDecodedAlert += _tcpConnectedLogic_RequestDecodedAlert;
  _tcpConnectedLogic.Start();

    }
编辑 当我停止服务时,我的线程并没有像我期望的那样关闭。而是以流产告终。为什么?我怎样才能使它优雅地靠近

protected override void OnStop()
{
    WriteToEventLog("Stop Command Received" + CurrentTimeStamp, entryType: EventLogEntryType.Information);
    WriteToLogFile("Stop Command Received @ " + CurrentTimeStamp);
    _shutdownEvent.Set();

    if (!_mainThread.Join(4000))
    {
        WriteToEventLog("OnStop: Aborting thread, Join did not work.  This is not preferred.", entryType: EventLogEntryType.Warning);
        _mainThread.Abort();
    }
}
在这个街区

while (!_shutdownEvent.WaitOne(0))
{
    IAsyncResult result = listener.BeginAcceptTcpClient(HandleAsyncConnection, listener);
    connectionWaitHandle.WaitOne();
}
您基本上是在循环中接受客户机,因为您通过等待connectionWaitHandle阻塞线程。您也可以忘记异步内容,只需执行以下操作:

while (!_shutdownEvent.WaitOne(0))
{                
     var client = listener.AcceptTcpClient();
     // start your logic in separate thread                
}
我并不是说您应该这样做,只是要注意,您当前的“异步”实现并没有比同步实现增加任何好处

然后,由于connectionWaitHandle上的相同阻塞,您在中止线程方面遇到了问题。例如,假设您刚刚启动了侦听器,但没有连接任何客户端。然后,客户端在connectionWaitHandle上被阻塞,而您设置的_shutdownEvent对这一事实没有帮助-主线程将永远没有机会检查它

解决此问题的最佳选择是使用基于任务的方法:

class Listener {
    // we don't use cancellation tokens because AcceptTcpClientAsync does not support them anyway
    private volatile bool _shutdown;
    private TcpListener _listener;

    public async Task Start() {
        _listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 10010);
        _listener.ExclusiveAddressUse = false;
        _listener.Start();
        while (!_shutdown) {
            TcpClient client = null;
            try {
                client = await _listener.AcceptTcpClientAsync();
            }
            catch (ObjectDisposedException) {
                // will be thrown when you stop listener   
            }
            if (client != null) {
                var tcpConnectedLogic = new TcpConnectionLogic(client);
                // start processing on thread pool thread if necessary
                // don't wait for it to finish - you need to accept more connections
                tcpConnectedLogic.StartAsync();
            }
        }
    }

    public void Stop() {
        _shutdown = true;
        _listener.Stop();
    }
}

使用async\await可以吗?响应时间问题必须来自此处不可见的代码。发布请求处理代码。@usr您是否建议我显示的代码正确实现?它有质量问题(请参见答案),但不应表现出特定的行为(高延迟)。MSDN示例令人讨厌。看看为什么这没有意义的答案。这不难理解。编写MSDN套接字代码的人不知道他做了什么。我如何实现tcpConnectedLogic.StartAsync()?我不明白你为什么说connectionWaitHandle不工作。代码应该等待等待,直到设置了等待句柄——这发生在新线程上的所有处理开始之前。因此,在收到客户机之后,我的理解是主线程继续循环,而之前的连接在新线程中继续,代码在我的逻辑层中。1。只要在线程池线程(Task.run(YourLogic))上运行所有逻辑即可。您最好在单独的线程上运行它,因为这样您就可以同时接受更多的连接。否则,在接受下一个客户端之前,您必须先处理一个客户端。connectionWaitHandle确实可以工作——但这样,您就可以通过等待该句柄来阻塞主线程,从而同步地接受连接。异步接受连接的要点是,等待不会阻塞任何线程。另外,您这样做会导致线程中止问题,如答案中所述。我正在尝试修改代码,但它不配合。谢谢你的提示,我会继续尝试,但暂时不行。