Многопоточный ответ для HttpListenerC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Многопоточный ответ для HttpListener

Сообщение Anonymous »

У меня есть однопоточный процесс, который выполняется некоторое время. Мне нужно, чтобы несколько пользователей имели доступ для выполнения этого процесса, и я выбираю протокол http для управления вызовом.

Естественно, когда один процесс работает, всем остальным следует подождать, пока он завершится. Если процесс доступен, он выполняется. Если нет, то отправляется ответ BUSY.

Вот реализация:

using System;
using System.Net;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;

namespace simplehttp
{
class Program
{
private static System.AsyncCallback task;
private static System.Threading.ManualResetEvent mre = new System.Threading.ManualResetEvent(false);// Notifies one or more waiting threads that an event has occurred.
private static HttpListenerContext workingContext = null;

public static bool isBackgroundWorking()
{
return mre.WaitOne(0);
}
static void Main(string[] args)
{
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
while (true)
{
Console.WriteLine(" waitOne " + isBackgroundWorking());
mre.WaitOne(); // Blocks the current thread until the current WaitHandle receives a signal.
Console.WriteLine(" do job" + " [" + Thread.CurrentThread.Name + ":" + Thread.CurrentThread.ManagedThreadId + " ]\n");
HttpListenerRequest request = workingContext.Request;
HttpListenerResponse response = workingContext.Response;
string responseString = "WORK " + DateTime.Now ;
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
System.IO.Stream output = response.OutputStream;
Thread.Sleep(10000);
output.Write(buffer, 0, buffer.Length);
output.Close();
Console.WriteLine(" " + responseString + "\t" + DateTime.Now);
workingContext = null;
mre.Reset(); // Sets the state of the event to nonsignaled, causing threads to block.
}
}).Start();

// Create a listener.
HttpListener listener = new HttpListener();

listener.Prefixes.Add("http://localhost:6789/index/");
listener.Start();
Console.WriteLine("Listening..." + " [" + Thread.CurrentThread.Name + ":" + Thread.CurrentThread.ManagedThreadId + " ]\n");

task = new AsyncCallback(ListenerCallback);

IAsyncResult resultM = listener.BeginGetContext(task,listener);
Console.WriteLine("Waiting for request to be processed asyncronously.");

Console.ReadKey();
Console.WriteLine("Request processed asyncronously.");
listener.Close();
}

private static void ListenerCallback(IAsyncResult result)
{
HttpListener listener = (HttpListener) result.AsyncState;

//If not listening return immediately as this method is called one last time after Close()
if (!listener.IsListening)
return;

HttpListenerContext context = listener.EndGetContext(result);
listener.BeginGetContext(task, listener);

if (workingContext == null && !isBackgroundWorking())
{
// Background work
workingContext = context;
mre.Set(); //Sets the state of the event to signaled, allowing one or more waiting threads to proceed.
}
else
{
HttpListenerRequest request = context.Request;
HttpListenerResponse response = context.Response;
string responseString = "BUSY "+ DateTime.Now + " [" + Thread.CurrentThread.Name + ":" + Thread.CurrentThread.ManagedThreadId;
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
System.IO.Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
output.Close();
Console.WriteLine(responseString + "\t" + DateTime.Now);
}
}
}
}


Для проверки я делаю 2 http-вызова. Я ожидаю, что у меня будет два разных ответа: РАБОТА и ЗАНЯТ.
Однако я вижу, что второй запрос сначала ожидает завершения, а затем выполняется.

waitOne False
Listening... [:10 ]

Waiting for request to be processed asyncronously.
do job [:11 ]

WORK 1/24/2016 10:34:01 AM 1/24/2016 10:34:11 AM
waitOne False
do job [:11 ]

WORK 1/24/2016 10:34:11 AM 1/24/2016 10:34:21 AM
waitOne False


Что не так в моем понимании того, как это должно работать?

Обновить (слишком много комментариев не поощряется СО):
Мой код выглядит неуклюже, потому что это копия реального процесса. В «моем» приложении рабочий процесс — это основной процесс, который «любезно» запускает встроенный код C# в определенные моменты. Итак, я не могу запустить новую задачу для обработки запроса, и она должна быть асинхронной, поскольку рабочий процесс выполняет свою собственную работу и вызывает только подчиненный фрагмент кода для уведомления клиентов о доступности данных. Это асинхронно, потому что код вызывается и должен завершиться как можно скорее, иначе оно заблокирует главное приложение.
Я попробую добавить дополнительный поток с синхронным вызовом и посмотрю, как это повлияет на ситуацию.

В этом примере отладчик не используется, чтобы не мешать процессу в реальном времени и меткам времени, выводимым на консоль. Отладка — это здорово и необходимо, но в этом случае я стараюсь заменить ее выводом, чтобы избежать лишнего участника в сценарии синхронизации/ожидания.

Само приложение не является сильно нагруженным диалогом. 1-3 клиента редко запрашивают ответ у основного приложения. Протокол http используется для удобства, а не для тяжелых или частых разговоров. Похоже, что некоторые браузеры, такие как IE, работают нормально (разговор между Windows и Windows?), а некоторые, такие как Chrome (более независимые от системы), повторяют поведение моего приложения. Посмотрите на отметки времени: Chrome, IE, IE, Chrome и последний Chrome все еще перешли в рабочий процесс. Кстати, код меняется для каждого предложения разговора, и теперь новый запрос размещается сразу после получения предыдущего.

HttpListenerContext context = listener.EndGetContext(result);
listener.BeginGetContext(task, listener);


Изображение


Кроме того, следуя рекомендациям, я заменил асинхронный вызов на синхронный, и результат остался прежним

private static void ListenerCallback(IAsyncResult result)
{
HttpListener listener = (HttpListener) result.AsyncState;

//If not listening return immediately as this method is called one last time after Close()
if (!listener.IsListening)
return;

HttpListenerContext context = listener.EndGetContext(result);

while (true)
{
if (workingContext == null && !isBackgroundWorking())
{
// Background work
workingContext = context;
mre.Set(); //Sets the state of the event to signaled, allowing one or more waiting threads to proceed.
}
else
{
HttpListenerRequest request = context.Request;
HttpListenerResponse response = context.Response;
string responseString = "BUSY " + DateTime.Now + " [" + Thread.CurrentThread.Name + ":" +
Thread.CurrentThread.ManagedThreadId;
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
System.IO.Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
output.Close();
Console.WriteLine(responseString + "\t" + DateTime.Now);
}
context=listener.GetContext();
}
}


Подробнее здесь: https://stackoverflow.com/questions/349 ... tplistener
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»