C# HTTPListener在四核机器Win 2008服务器R2上崩溃
我们基于EWS手册中的HTTPListener创建了am Exchange Web服务推送通知侦听器(代码如下)。它在Win2008服务器上使用单核xeon运行良好。现在,我们将它移动到一个带有四核opteron CPU的Win 2008 R2服务器上,在侦听器使用HTTPListenerExceptions初始化后,它立即崩溃。现在,除了服务器之外,没有任何变化,我想这可能与多线程有关。也许有人可以给你建议,谢谢C# HTTPListener在四核机器Win 2008服务器R2上崩溃,c#,multithreading,service,windows-server-2008,httplistener,C#,Multithreading,Service,Windows Server 2008,Httplistener,我们基于EWS手册中的HTTPListener创建了am Exchange Web服务推送通知侦听器(代码如下)。它在Win2008服务器上使用单核xeon运行良好。现在,我们将它移动到一个带有四核opteron CPU的Win 2008 R2服务器上,在侦听器使用HTTPListenerExceptions初始化后,它立即崩溃。现在,除了服务器之外,没有任何变化,我想这可能与多线程有关。也许有人可以给你建议,谢谢 public class PushNotificationClient {
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");
}
}
}
公共类PushNotificationClient
{
专用uint端口号;
私有NotificationEventsReceivedEventHandler;
私有bool isListening=false;
private ManualResetEvent stopEvent=新的ManualResetEvent(错误);
private bool shouldStop=false;
私人空间经理;;
私有XmlSerializer;
///
///建造师
///
///要侦听的端口号
///在发送通知时要调用的委托
///收到
///
公共推送通知客户端(
uint端口号,
NotificationEventsReceived eventHandler)
{
this.portNumber=portNumber;
if(eventHandler==null)
{
抛出新ArgumentNullException(“eventHandler”);
}
this.eventHandler=eventHandler;
//命名空间管理器用于解析请求时的XPath查询
//
this.mgr=new-XmlNamespaceManager(new-NameTable());
此.mgr.AddNamespace(“t”,
"http://schemas.microsoft.com/exchange/services/2006/types");
此.mgr.AddNamespace(“m”,
"http://schemas.microsoft.com/exchange/services/2006/messages");
//XmlSerializer用于将SendNotification元素转换为代理
//类实例
//
this.ser=新的XmlSerializer(typeof(SendNotificationResponseType));
}
///
///开始听
///
公营机构
{
VerifyNotListing();
此参数为.stopEvent.Reset();
this.shouldStop=false;
//在后台线程上运行侦听器,这样我们就不会被阻止
//
QueueUserWorkItem(新的WaitCallback(ListenOnThread));
}
///
///别再听了
///
公营部门
{
验证听力();
//设置stopEvent。这将导致工作线程关闭和
//处置HttpListener并退出线程
//
this.stopEvent.Set();
}
///
///线程池方法开始侦听后台线程
///
///状态-忽略
///
私有void listenothread(对象状态)
{
使用(HttpListener=newHttpListener())
{
listener.Prefixes.Add(
字符串格式(
“http://+:{0}/PushNotificationsClient/”,
this.portNumber.ToString());
listener.Start();
this.isListening=true;
而(!应该停止)
{
IAsyncResult asyncResult=listener.BeginGetContext(
异步回调方法,侦听器);
//等待侦听器或停止事件
//
int index=WaitHandle.WaitAny(
新的WaitHandle[]{stopEvent,asyncResult.AsyncWaitHandle});
开关(索引)
{
案例0:
//已触发停止事件。
//
shouldStop=true;
打破
案例1:
//已收到通知。请循环,以便我们可以呼叫
//重新开始上下文
//
打破
}
}
listener.Stop();
}
this.isListening=false;
}
///
///收到请求后调用异步方法
///
///包含HttpListener的异步结果
///
私有void AsyncCallbackMethod(IAsyncResult结果)
{
HttpListener listener=result.AsyncState作为HttpListener;
如果(!this.isListening)
{
//当我们停止侦听器时,我们的回调也会被触发
//听着,回来吧。
//
返回;
}
HttpListenerContext=listener.EndGetContext(结果);
SendNotificationResponseType请求;
//现在使用XML序列化程序将XML转换为通知
//序列化类型。。。
//
XmlDocument doc=新的XmlDocument();
尝试
{
doc.LoadXml(
新的流阅读器(
ReadToEnd());
//检索第一个SendNotification元素(应该只有一个)。
//
XmlNodeList nodes=doc.SelectNodes(“//m:SendNotification[1]”,this.mgr);
如果(nodes.Count==0)
{
//这不是SendNotification请求,或者格式不正确或
//差不多吧。
失败请求(上下文);
返回;
}
字符串sendNotification=节点[0]。OuterXml;
使用(MemoryStream ms=new MemoryStream())
{
字节[]字节=Encoding.UTF8.GetBytes(sendNotification);
ms.Write(字节,0,字节.长度);
弗拉什女士();
ms.位置=0升;
request=(SendNotificationResponseType)this.ser.反序列化(ms);
}
}
捕获(XmlException)
{
//未能反序列化请求。
//
失败请求(上下文);
返回;
}
//解雇代表
//
NotificationResponse=eventHandler(
这是,/*发件人*/
request.ResponseMessages.Items[0]