2011-01-26 5 views
4

Я написал службу Windows, используя HttpListener для асинхронной обработки запросов из точек.Проблема с C# с HttpListener

Он отлично работает, но иногда он сталкивается с проблемой, требующей перезапуска службы или сервера для исправления. Первоначально я объявил объект слушателя:

public HttpListener PointsListener = new HttpListener(); 

Вот код метода, где я начинаю слушать. Я звоню его из OnStart метода обслуживания:

public string ListenerStart() 
    { 
     try 
     { 
      if (!PointsListener.IsListening) 
      { 
       PointsListener.Prefixes.Add(String.Concat("http://*:", points_port, "/")); 
       PointsListener.Start(); 
       PointsListener.BeginGetContext(PointProcessRequest, PointsListener); 

       LogWriter("Http listener activated on port " + points_port); 
       return "Listener started"; 
      } 
      else 
      { 
       return "Listener is already started!"; 
      } 

     } 
     catch (Exception err) 
     { 
      LogWriter("Error in LIstenerStart \r\n" + err.ToString()); 
      return ("Error: " + err.Message); 
     } 
    } 

Вот методы, обрабатывать запросы:

private void PointProcessRequest(IAsyncResult result) 
    { 
     HttpListener listener = (HttpListener)result.AsyncState; 
     HttpListenerContext context = listener.EndGetContext(result); 
     HttpListenerRequest request = context.Request; 
     HttpListenerResponse response = context.Response; 
     response.KeepAlive = false; 
     System.IO.Stream output = response.OutputStream; 

     try 
     { 
      //declaring a variable for responce 
      string responseString = "<html>My Response: request is not allowed by server protocol</html>"; 


      // Commands and actions to set responceString 

      byte[] buffer = Encoding.UTF8.GetBytes(responseString); 
      response.ContentLength64 = buffer.Length; 
      output.Write(buffer, 0, buffer.Length); 
     } 
     catch (Exception err) 
     { 
      LogWriter("Error in PointProcessRequest: \r\n" + err.ToString()); 
     } 
     finally 
     { 
      try 
      { 
       output.Flush(); 
       output.Close(); 
       response.Close(); 
      } 
      catch (Exception err) 
      { 
       LogWriter("Error in PointProcessRequest CLOSING OUTPUT STREAM: \r\n" + err.ToString()); 
      } 
      finally 
      { 
       PointsListener.BeginGetContext(PointProcessRequest, PointsListener); 
      } 
     } 
    } 

Это работает хорошо некоторое время, но появляется следующее сообщение об ошибке в бланк:

Error in PointProcessRequest: 
System.Net.HttpListenerException: The specified network name is no longer available 
    в System.Net.HttpResponseStream.Write(Byte[] buffer, Int32 offset, Int32 size) 
    в ARK_Dealer.ark.PointProcessRequest(IAsyncResult result) 

[26.01.2011 9:00:54] Error in PointProcessRequest CLOSING OUTPUT STREAM: 
System.InvalidOperationException: Cannot close stream until all bytes are written. 
    в System.Net.HttpResponseStream.Dispose(Boolean disposing) 
    в System.IO.Stream.Close() 
    в ARK_Dealer.ark.PointProcessRequest(IAsyncResult result) 

Я думаю, что проблема возникает, когда какая-то точка отправляет запрос на сервер, но до того, как принимающий ответ теряет соединение.

Как я могу предотвратить исключение исключения? Будет ли объект ответа правильно удаляться автоматически? Как я могу решить проблему?

ответ

2

Об этом есть related question.

Что вы делаете, это нормально, поскольку нет ничего другого, что можно было бы сделать с другой стороны, закрывающей соединение или удаляемое соединение. Вы можете захотеть поймать точное исключение и вызвать output.Dispose() и другую очистку или просто позволить финализаторам обрабатывать выпуск, если это происходит не очень часто.

+0

Я немного закодировал метод PointProcess и вставил Dispose там, как вы писали. Позвольте мне контролировать систему несколько дней, чтобы увидеть, будет ли она вступать в силу или нет. Большое спасибо! – Khisrav

+0

Привет! Прошу прокомментировать мое окончательное решение, при написании ответа на выходной поток я использую следующий код: using (System.IO.Stream output = response.OutputStream) { output.Write (buffer, 0, buffer.Length); } Если произойдет исключение, оно будет записано в журнал, и если код будет запущен, вывод объекта будет удален автоматически. Я прав? Спасибо! – Khisrav

+0

Вы все еще закрываете объект 'response'? – Amir

2

У меня была та же проблема, в последнее время, и решить ее, окружив выход в Try/уловом:

try 
{ 
    byte[] buffer = Encoding.UTF8.GetBytes(responseString); 
    response.ContentLength64 = buffer.Length; 
    output.Write(buffer, 0, buffer.Length); 
} 
catch (HttpListenerException) 
{ 
    // Handle error caused by connection being lost 
} 
+0

Как вы видите в моем коде, это уже в try catch, поэтому я могу регистрировать исключение, и слушатель не останавливается ... Но я пытаюсь найти решение, предотвращающее запись в выходной поток, если текущее соединение больше недоступно. Спасибо. – Khisrav

2

Проблема решена !!! Я просто удалил это:

finally 
{ 
PointsListener.BeginGetContext(PointProcessRequest, PointsListener); 
} 

и вставил эту команду в начале метода PointProcessRequest!

IAsyncResult _result = listener.BeginGetContext(new AsyncCallback(PointProcessRequest), listener); 

Проблема решена на 100% !!!

4

Я использую HttpListener в производстве, и я нашел самый лучший способ решить эту проблему, не добавляя целую кучу блоков try/catch, которые ничего не делают для передачи логики кода под рукой; достаточно просто установить Listener.IgnoreWriteExceptions = true; и, вуаля больше не писать исключений!

+5

Это не так на многих уровнях! Что делать, если вы постоянно пишете поток, а другая сторона закрывает соединение по какой-то причине, вы не получите исключение, вызванное вызовом Write(), потому что вы игнорируете записи исключений, и ваше приложение будет продолжать писать в поток, который ему кажется открытым ... – Cipi

+2

IgnoreWriteExceptions - это путь. Я не согласен с Cipi и его «краевым случаем», который даже не имеет смысла для протокола HTTP. –

+2

@ Lubos, ответ Ципи имеет прекрасный смысл. Что делать, если ваш запрос предназначен для загрузки большого файла. Если вы проигнорируете исключения, вы продолжите читать из файла, даже если байты никогда не достигнут клиента. –