【问题标题】:HttpListner stops on executing thread.Join()Http Listener 在执行 thread.Join() 时停止
【发布时间】:2013-07-03 17:14:20
【问题描述】:

通过使用这个code,我创建了一个HttpListner 来为某些站点向浏览器发送自定义消息。代码正常工作,消息正在显示。但是,当我试图停止 Httpserver 时,应用程序在此行被阻止: _listenerThread.Join(); 我是 threading 新手,所以对我如何使我的代码工作有任何帮助。 下面是我的代码

private readonly HttpListener _listener;
private readonly Thread _listenerThread;
private readonly Thread[] _workers;
private readonly ManualResetEvent _stop, _ready;
private Queue<HttpListenerContext> _queue;


public HttpServer(int MaxThreads)
{
    _workers = new Thread[MaxThreads];
    _queue = new Queue<HttpListenerContext>();
    _stop = new ManualResetEvent(false);
    _ready = new ManualResetEvent(false);
    _listener = new HttpListener();
    _listenerThread = new Thread(HandleRequests);
}

private void HandleRequests()
{
    while (_listener.IsListening)
    {

        var context = _listener.BeginGetContext(GetContextCallBack, null);

        if (0 == WaitHandle.WaitAny(new WaitHandle[] { _stop, context.AsyncWaitHandle }))
        {
            return;
        }
    }
}

private void GetContextCallBack(IAsyncResult result)
{
    try
    {
        lock(_queue)
        {
            _queue.Enqueue(_listener.EndGetContext(result));                   
            _ready.Set();
         }
    }
    catch
    { return; }

}

public void Start(int port)
{
    _listener.Prefixes.Add(String.Format(@"http://+:{0}/", port));
    _listener.Start();
    _listenerThread.Start();

    for (int i = 0; i < _workers.Length; i++)
    {
        _workers[i] = new Thread(Worker);
        _workers[i].Start();
    }
}

private void Worker(object obj)
{
    WaitHandle[] wait = new[] { _ready, _stop };
    while (0 == WaitHandle.WaitAny(wait))
    {
        HttpListenerContext context;
        lock (_queue)
        {
            if (_queue.Count > 0)
                context = _queue.Dequeue();
            else
            {
                _ready.Reset();
                continue;
            }
        }

        try
        {
            ProcessRequest(context);
        }
        catch(Exception ex)
        {
            MessageBox.Show(ex.Message + ex.StackTrace);
        }

    }
}

public void Dispose()
{
    Stop();
}

private void Stop()
{
    try
    {
        _stop.Reset();
        _listenerThread.Join();
        foreach (Thread worker in _workers)
        {
            worker.Join();
        }
        _listener.Stop();
        App.Current.MainWindow.Close();

    }
    catch(Exception ex)
    {
        MessageBox.Show(ex.Message + ex.StackTrace);
    }
}


public void  ProcessRequest(HttpListenerContext context)
{
    HttpListenerRequest request = context.Request;
    HttpListenerResponse response = context.Response;

    System.Text.StringBuilder sb = new StringBuilder();

    sb.Append("");
    sb.Append(string.Format("HttpMethod: {0}", request.HttpMethod));
    sb.Append(string.Format("Uri:        {0}", request.Url.AbsoluteUri));
    sb.Append(string.Format("LocalPath:  {0}", request.Url.LocalPath));
    foreach (string key in request.QueryString.Keys)
    {
        sb.Append(string.Format("Query:      {0} = {1}", key, request.QueryString[key]));
    }

    sb.Append("");

    string responseString = sb.ToString();
    byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
    response.ContentLength64 = buffer.Length;

    using (System.IO.Stream outputStream = response.OutputStream)
    {
        outputStream.Write(buffer, 0, buffer.Length);
    }
}

此代码也可能对希望将自定义消息发送到网络浏览器的其他人有所帮助。

【问题讨论】:

  • WPF 是从哪里来的?
  • 我正在制作一个 WPF 应用程序。并在许多地方搜索了如何向浏览器发送自定义消息,但无法找到它。结合几个不同帖子的答案来提出此代码。希望这可能有助于将来制作应用程序的人。
  • 虽然您很可能正在创建 WPF 应用程序,但它根本不会影响问题 - 您的代码中没有任何内容涉及 WPF 或其中的任何约束。

标签: c# wpf multithreading httplistener


【解决方案1】:

这是“停止”线程中的第一个问题:

_listenerThread.Join();
...
_listener.Stop();

在您告诉侦听器停止侦听之前,您正在等待侦听器线程停止...但是侦听器线程有:

private void HandleRequests()
{
    while (_listener.IsListening)
    {
        ...
    }
}

...所以它只会在监听器停止之后终止。你基本上陷入了僵局。您应该更改停止代码的顺序:

_listener.Stop();
_listenerThread.Join();
...

另外这一行:

_stop.Reset();

应该是:

_stop.Set();

因为你想发出信号你正在停止 - 不要清除信号。

【讨论】:

  • @g10:不,因为你仍然会在监听线程中永远循环。
猜你喜欢
  • 2013-03-11
  • 2014-05-24
  • 1970-01-01
  • 1970-01-01
  • 2015-02-12
  • 1970-01-01
  • 2018-11-07
  • 1970-01-01
  • 2016-06-30
相关资源
最近更新 更多