简体   繁体   English

HTTPListener在四核机器Win 2008 Server R2上崩溃

[英]HTTPListener crashes on quad core machine Win 2008 Server R2

we created am Exchange Web Service Push Notifications Listener based on the HTTPListener in the EWS book (code below). 我们基于EWS书中的HTTPListener创建了一个Exchange Web Service推送通知监听器(以下代码)。 It ran just fine on a Win 2008 Server with a single core xeon. 它在带有单核xeon的Win 2008 Server上运行得很好。 Now we moved it to a Win 2008 R2 Server with a quad core opteron CPU and it immediately crashes after the Listener is initialized with HTTPListenerExceptions. 现在我们将它移动到带有四核opteron CPU的Win 2008 R2服务器,并在使用HTTPListenerExceptions初始化Listener后立即崩溃。 Now since nothing changed but the Server I thought it might have something to do with multi threading. 现在,既然服务器什么都没有改变,我认为它可能与多线程有关。 Maybe someon can advise, thank you. 也许某人可以提供建议,谢谢。

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


}

It would help if you told us where in the initialization it was failing, but I suspect that you're either trying to register a URI that you haven't enabled with the netsh command, or you're trying to register a URI that some other process already has registered. 如果您告诉我们初始化失败的地方会有所帮助,但我怀疑您要么尝试注册未使用netsh命令启用的URI,要么尝试注册一些URI其他流程已经注册。

Documentation for that exception says, in part: 该异常的文档部分说明:

HttpListenerException will be thrown if the HttpListener attempts to register a Uniform Resource Identifier (URI) prefix that is already registered. HttpListenerException如果将被抛出HttpListener尝试注册一个已经注册的统一资源标识符(URI)前缀。

Has some other process already registered http://+:{0}/PushNotificationsClient/ ? 是否已经有其他进程注册了http://+:{0}/PushNotificationsClient/ Did you remember to run the netsh command to register the URI on the correct port and allow listening? 你还记得运行netsh命令在正确的端口上注册URI并允许监听吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM