HttpListner останавливается при выполнении thread.Join()

Вопрос:

Используя этот код, я создал HttpListner для отправки пользовательских сообщений в браузер для некоторых сайтов. Код работает правильно, и сообщение отображается. Но, когда я пытаюсь остановить Httpserver, приложение блокируется в этой строке: _listenerThread.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);
}
}

Этот код может помочь другим пользователям, которые хотят отправлять пользовательские сообщения в веб-браузер.

Лучший ответ:

Это первая проблема в потоке «остановки»:

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

Вы ожидаете, когда поток слушателя остановится, прежде чем вы скажете слушателю прекратить прослушивание… но поток слушателя:

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

… поэтому он прекратится только после того, как слушатель остановится. У тебя в тупике. Вы должны изменить порядок кода остановки:

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

Дополнительно эта строка:

_stop.Reset();

должно быть:

_stop.Set();

так как вы хотите сигнализировать о том, что вы останавливаете — не очистить сигнал.

Оцените статью
TechArks.Ru
Добавить комментарий