2013-07-05 82 views
0

通過使用此code我創建了一個HttpListner來發送自定義消息給瀏覽器的一些網站。代碼正常工作,消息正在顯示。但是,當我試圖阻止Httpserver時,應用程序在此行中被阻止: _listenerThread.Join(); 我是線程新手,所以對如何讓我的代碼能夠工作有幫助。 下面是我的代碼HttpListner停止執行thread.Join()

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); 
    } 
} 

此代碼可以幫助別人過誰正在尋找發送自定義消息的網頁瀏覽器。

+0

WPF進入這個怎麼辦? –

+0

我正在製作一個WPF應用程序。並在許多地方搜索如何發送自定義消息到瀏覽器,但無法找到它。從幾個不同的帖子結合答案來提出這個代碼。希望這可能有助於在未來的一個人提出申請。 – g10

+0

儘管您可能正在創建一個WPF應用程序,但它根本不會影響該問題 - 代碼中沒有任何內容引用WPF或其中的任何約束。 –

回答

0

這是「停止」線程的第一個問題:

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

你在等待的監聽線程你告訴聽者停止監聽前停止......但聽者線程:

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

...所以它只會終止後,聽衆已停止。你基本上已經陷入僵局。你應該改變的停止代碼的順序:

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

此外,該行:

_stop.Reset(); 

應該是:

_stop.Set(); 

只要你想信號,你停止 - 不清除信號。

+0

只會更改_stop.Set()工作 – g10

+0

@ g10:不,因爲您仍然會在偵聽器線程中循環巡迴。 –