0

Nous avons créé un programme d'écoute de notifications Push du service Web Exchange basé sur le HTTPListener du livre EWS (code ci-dessous). Il fonctionnait très bien sur un serveur Win 2008 avec un seul noyau xeon. Maintenant, nous l'avons déplacé vers un serveur Win 2008 R2 avec un processeur opteron quad core et il se bloque immédiatement après l'initialisation de Listener avec HTTPListenerExceptions. Maintenant, puisque rien n'a changé, mais le serveur, je pensais que cela pourrait avoir quelque chose à voir avec le multi-threading. Peut-être que quelqu'un peut vous conseiller, merci.HTTPListener se bloque sur une machine quad core Win 2008 Server R2

public class PushNotificationClient 
{ 
    private uint portNumber; 
    private NotificationEventsReceived eventHandler; 
    private bool isListening = false; 
    private ManualResetEvent stopEvent = new ManualResetEvent(false); 
    private bool shouldStop = false; 
    private XmlNamespaceManager mgr; 
    private XmlSerializer ser; 

    /// <summary> 
    /// Constructor 
    /// </summary> 
    /// <param name="portNumber">Port number to listen on</param> 
    /// <param name="eventHandler">delegate to call when notifications are 
    /// received</param> 
    /// 
    public PushNotificationClient(
    uint portNumber, 
    NotificationEventsReceived eventHandler) 
    { 
     this.portNumber = portNumber; 
     if (eventHandler == null) 
     { 
      throw new ArgumentNullException("eventHandler"); 
     } 
     this.eventHandler = eventHandler; 
     // namespace manager is used for XPath queries when parsing the request 
     // 
     this.mgr = new XmlNamespaceManager(new NameTable()); 
     this.mgr.AddNamespace("t", 
     "http://schemas.microsoft.com/exchange/services/2006/types"); 
     this.mgr.AddNamespace("m", 
     "http://schemas.microsoft.com/exchange/services/2006/messages"); 
     // XmlSerializer is used to convert SendNotification elements into proxy 
     // class instances 
     // 
     this.ser = new XmlSerializer(typeof(SendNotificationResponseType)); 
    } 

    /// <summary> 
    /// Start Listening 
    /// </summary> 
    public void StartListening() 
    { 
     VerifyNotListening(); 
     this.stopEvent.Reset(); 
     this.shouldStop = false; 
     // Run the listener on a background thread so we are not blocked 
     // 
     ThreadPool.QueueUserWorkItem(new WaitCallback(ListenOnThread)); 
    } 

    /// <summary> 
    /// Stop Listening 
    /// </summary> 
    public void StopListening() 
    { 
     VerifyListening(); 
     // Set the stopEvent. This will cause the worker thread to close our and 
     // dispose of the HttpListener and exit the thread 
     // 
     this.stopEvent.Set(); 
    } 

    /// <summary> 
    /// Thread pool method to start listening on the background thread 
    /// </summary> 
    /// <param name="state">State - ignore</param> 
    /// 
    private void ListenOnThread(object state) 
    { 
     using (HttpListener listener = new HttpListener()) 
     { 
      listener.Prefixes.Add(
       String.Format(
       "http://+:{0}/PushNotificationsClient/", 
       this.portNumber.ToString())); 
      listener.Start(); 
      this.isListening = true; 
      while (!shouldStop) 
      { 
       IAsyncResult asyncResult = listener.BeginGetContext(
       AsyncCallbackMethod, listener); 
       // Wait on either the listener or the stop event 
       // 
       int index = WaitHandle.WaitAny(
       new WaitHandle[] { stopEvent, asyncResult.AsyncWaitHandle }); 
       switch (index) 
       { 
        case 0: 
         // Stop event was triggered. 
         // 
         shouldStop = true; 
         break; 
        case 1: 
         // Notification was received. Just loop around so we can call 
         // BeginGetContext again 
         // 
         break; 
       } 
      } 
      listener.Stop(); 
     } 
     this.isListening = false; 
    } 

    /// <summary> 
    /// Async method called once we receive a request 
    /// </summary> 
    /// <param name="result">Async result containing our HttpListener</param> 
    /// 
    private void AsyncCallbackMethod(IAsyncResult result) 
    { 
     HttpListener listener = result.AsyncState as HttpListener; 
     if (!this.isListening) 
     { 
      // Our callback gets fired when we stop the listener too. If it is not 
      // listening, just return. 
      // 
      return; 
     } 
     HttpListenerContext context = listener.EndGetContext(result); 
     SendNotificationResponseType request; 
     // Now use the XML serializer to turn the XML into a notification 
     // serialization type... 
     // 
     XmlDocument doc = new XmlDocument(); 
     try 
     { 
      doc.LoadXml(
      new StreamReader(
      context.Request.InputStream).ReadToEnd()); 
      // retrieve the first SendNotification element (there should be only one). 
      // 
      XmlNodeList nodes = doc.SelectNodes("//m:SendNotification[1]", this.mgr); 
      if (nodes.Count == 0) 
      { 
       // this wasn't a SendNotification request or it was malformed or 
       // something like that. 
       FailRequest(context); 
       return; 
      } 
      string sendNotification = nodes[0].OuterXml; 
      using (MemoryStream ms = new MemoryStream()) 
      { 
       byte[] bytes = Encoding.UTF8.GetBytes(sendNotification); 
       ms.Write(bytes, 0, bytes.Length); 
       ms.Flush(); 
       ms.Position = 0L; 
       request = (SendNotificationResponseType)this.ser.Deserialize(ms); 
      } 
     } 
     catch (XmlException) 
     { 
      // Failed to deserialize request. 
      // 
      FailRequest(context); 
      return; 
     } 
     // Fire the delegate 
     // 
     NotificationResponse response = eventHandler(
     this, /* sender */ 
     request.ResponseMessages.Items[0] 
     as SendNotificationResponseMessageType); 
     GenerateResponseXML(context, response); 
    } 

    /// <summary> 
    /// Fail the request. Right now we don't differentiate between reasons why it 
    /// failed. 
    /// </summary> 
    /// <param name="context">Request context</param> 
    /// 
    private void FailRequest(HttpListenerContext context) 
    { 
     context.Response.ContentEncoding = Encoding.UTF8; 
     context.Response.ContentType = "text/xml; charset=utf-8"; 
     context.Response.ProtocolVersion = new Version(1, 1, 0, 0); 
     context.Response.StatusCode = 400; 
     string response = "<?xml version=\"1.0\"?>" + 
     "<Error>Bad Request</Error>"; 
     byte[] responseBytes = Encoding.UTF8.GetBytes(response); 
     context.Response.ContentLength64 = responseBytes.Length; 
     context.Response.OutputStream.Write(
     responseBytes, 0, responseBytes.Length); 
     context.Response.OutputStream.Flush(); 
    } 

    /// <summary> 
    /// Generate the response xml 
    /// </summary> 
    /// <param name="context">call context</param> 
    /// <param name="response">The response enum value</param> 
    /// 
    private void GenerateResponseXML(
    HttpListenerContext context, 
    NotificationResponse response) 
    { 
     StringBuilder builder = new StringBuilder(); 
     builder.AppendLine("<?xml version=\"1.0\"?>"); 
     builder.AppendLine("<s:Envelope xmlns:s= " + 
     "\"http://schemas.xmlsoap.org/soap/envelope/\">"); 
     builder.AppendLine("<s:Body>"); 
     builder.AppendLine(" <SendNotificationResult " + 
     "xmlns=\"http://schemas.microsoft.com/exchange/services/2006/messages\">"); 
     builder.AppendFormat(" <SubscriptionStatus>{0}</SubscriptionStatus>\r\n", 
     response.ToString()); 
     builder.AppendLine(" </SendNotificationResult>"); 
     builder.AppendLine("</s:Body>"); 
     builder.AppendLine("</s:Envelope>"); 
     context.Response.ContentEncoding = Encoding.UTF8; 
     context.Response.ContentType = "text/xml; charset=utf-8"; 
     context.Response.ProtocolVersion = new Version(1, 1, 0, 0); 
     context.Response.StatusCode = 200; 
     byte[] responseBytes = Encoding.UTF8.GetBytes(builder.ToString()); 
     context.Response.ContentLength64 = responseBytes.Length; 
     context.Response.OutputStream.Write(
     responseBytes, 0, responseBytes.Length); 
     context.Response.OutputStream.Flush(); 
    } 

    /// <summary> 
    /// Returns true if the listener is listening 
    /// </summary> 
    public bool IsListening 
    { 
     get 
     { 
      return isListening; 
     } 
    } 
    /// <summary> 
    /// Verifies that the listener isn't listening 
    /// </summary> 
    private void VerifyNotListening() 
    { 
     if (isListening) 
     { 
      throw new PushNotificationStateException("Cannot perform this operation " + 
      "when listening"); 
     } 
    } 

    /// <summary> 
    /// Verifies that the listener is listening 
    /// </summary> 
    private void VerifyListening() 
    { 
     if (!isListening) 
     { 
      throw new PushNotificationStateException("Cannot perform this operation " + 
      "when not listening"); 
     } 
    } 


} 
+0

Vous ne posez pas cette question de manière intelligente. L'exception pourrait ne pas signifier quelque chose pour vous mais cela nous concerne. Message de message + trace de pile. –

Répondre

2

Il serait utile que vous nous avez dit où dans l'initialisation, il a été un échec, mais je soupçonne que vous êtes soit d'essayer d'enregistrer un URI que vous n'avez pas activé avec la commande netsh, ou que vous êtes essayer d'enregistrer un URI qu'un autre processus a déjà enregistré.

Documentation cette exception dit, en partie:

HttpListenerException seront jetés si les tentatives de HttpListener enregistrer un Uniform Resource Identifier préfixe (URI) qui est déjà enregistré.

Un autre processus a-t-il déjà été enregistré http://+:{0}/PushNotificationsClient/? Avez-vous pensé à exécuter la commande netsh pour enregistrer l'URI sur le port approprié et permettre l'écoute?

+0

Salut, non, je n'ai pas exécuté la commande netsh, je viens d'apprendre à ce sujet puisque nous n'avons jamais eu à l'utiliser sur la machine Windows 2008 Server R1. Je vais essayer cette première chose le matin, merci! – hoetz

Questions connexes