Сбой HTTPListener на четырехъядерном компьютере Win 2008 Server R2 - PullRequest
0 голосов
/ 19 ноября 2010

мы создали прослушиватель push-уведомлений веб-службы Exchange на основе HTTPListener в книге EWS (код ниже). Он отлично работал на Win 2008 Server с одноядерным Xeon. Теперь мы переместили его на Win 2008 R2 Server с четырехъядерным процессором Opteron, и он сразу же вышел из строя после инициализации прослушивателя с HTTPListenerExceptions. Теперь, поскольку ничего не изменилось, кроме Сервера, я подумал, что это может быть связано с многопоточностью. Может быть, кто-то может посоветовать, спасибо.

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


}

1 Ответ

2 голосов
/ 19 ноября 2010

Было бы полезно, если бы вы сказали нам, где при инициализации произошел сбой, но я подозреваю, что вы либо пытаетесь зарегистрировать URI, который вы не включили с помощью команды netsh, либо пытаетесьзарегистрируйте URI, который уже зарегистрирован другим процессом.

Документация для этого исключения говорит, в частности:

HttpListenerException будет выдано, если1010 * пытается зарегистрировать префикс универсального идентификатора ресурса (URI), который уже зарегистрирован.

Уже зарегистрирован какой-то другой процесс http://+:{0}/PushNotificationsClient/?Вы не забыли запустить команду netsh, чтобы зарегистрировать URI на правильном порту и разрешить прослушивание?

...