2011-06-20 83 views
5

我正在做第一次試驗Comet的嘗試。我開發了一個非常簡單的聊天網絡應用程序 - 基本上是一個通過c#編寫的comet世界。我遇到的問題是IIS有時會崩潰,並通過崩潰我的意思是它只是停止響應HTTP請求。然後,它需要重新啓動應用程序池,有時還需要重新啓動整個IIS服務。我幾乎是積極的罪魁禍首是我用來阻止彗星請求線程的ManualResetEvent對象,直到收到釋放(更新)這些線程的信號。我嘗試編寫一個HTTP處理程序來解決這個問題,並將可重用屬性設置爲false(將新的請求線程置於另一個ManualResetEvent對象實例上),但這並不奏效。我也在嘗試實現IRegisteredObject,所以我可以在應用程序關閉時釋放這些內容,但這似乎也不起作用。它仍然崩潰,似乎沒有任何模式,當它崩潰(我已經注意到)。我幾乎可以肯定它是靜態實例和使用ManualResetEvent的組合。我只是不確定如何或如何解決這個問題。c#彗星服務器凍結IIS

Comet.cs(我的簡單彗星LIB)

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Net.Mail; 
using System.Web.Hosting; 

namespace Comet 
{ 
    public class CometCore : IRegisteredObject 
    { 
     #region Globals 
     private static CometCore m_instance = null; 
     private List<CometRequest> m_requests = new List<CometRequest>(); 
     private int m_timeout = 120000; //Default - 20 minutes; 
     #endregion 

     #region Constructor(s) 
     public CometCore() 
     { 
      HostingEnvironment.RegisterObject(this); 
     } 
     #endregion 

     #region Properties 
     /// <summary> 
     /// Singleton instance of the class 
     /// </summary> 
     public static CometCore Instance 
     { 
      get 
      { 
       if (m_instance == null) 
        m_instance = new CometCore(); 
       return m_instance; 
      } 
     } 

     /// <summary> 
     /// In milliseconds or -1 for no timeout. 
     /// </summary> 
     public int Timeout { get { return m_timeout; } set { m_timeout = value; } } 
     #endregion 

     #region Public Methods 
     /// <summary> 
     /// Pauses the thread until an update command with the same id is sent. 
     /// </summary> 
     /// <param name="id"></param> 
     public void WaitForUpdates(string id) 
     { 
      //Add this request (and thread) to the list and then make it wait. 
      CometRequest request; 
      m_requests.Add(request = new CometRequest(id)); 

      if (m_timeout > -1) 
       request.MRE.WaitOne(m_timeout); 
      else 
       request.MRE.WaitOne(); 
     } 

     /// <summary> 
     /// Un-pauses the threads with this id. 
     /// </summary> 
     /// <param name="id"></param> 
     public void SendUpdate(string id) 
     { 
      for (int i = 0; i < m_requests.Count; i++) 
      { 
       if (m_requests[i].ID.Equals(id)) 
       { 
        m_requests[i].MRE.Set(); 
        m_requests.RemoveAt(i); 
        i--; 
       } 
      } 
     } 
     #endregion 

     public void Stop(bool immediate) 
     { 
      //release all threads 
      for (int i = 0; i < m_requests.Count; i++) 
      { 
       m_requests[i].MRE.Set(); 
       m_requests.RemoveAt(i); 
       i--; 
      } 
     } 
    } 

    public class CometRequest 
    { 
     public string ID = null; 
     public ManualResetEvent MRE = new ManualResetEvent(false); 
     public CometRequest(string pID) { ID = pID; } 
    } 
} 

我的聊天類和Web服務

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.Services; 
using Comet; 

namespace CometTest 
{ 
    /// <summary> 
    /// Summary description for Chat 
    /// </summary> 
    [WebService(Namespace = "http://tempuri.org/")] 
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] 
    [System.ComponentModel.ToolboxItem(false)] 
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
    [System.Web.Script.Services.ScriptService] 
    public class Chat : System.Web.Services.WebService 
    { 

     [WebMethod] 
     public string ReceiveChat() 
     { 
      return ChatData.Instance.GetLines(); 
     } 

     [WebMethod] 
     public string ReceiveChat_Comet() 
     { 
      CometCore.Instance.WaitForUpdates("chat"); 
      return ChatData.Instance.GetLines(); 
     } 

     [WebMethod] 
     public void Send(string line) 
     { 
      ChatData.Instance.Add(line); 
      CometCore.Instance.SendUpdate("chat"); 
     } 
    } 

    public class ChatData 
    { 
     private static ChatData m_instance = null; 
     private List<string> m_chatLines = new List<string>(); 
     private const int m_maxLines = 5; 

     public static ChatData Instance 
     { 
      get 
      { 
       if (m_instance == null) 
        m_instance = new ChatData(); 
       return m_instance; 
      } 
     } 

     public string GetLines() 
     { 
      string ret = string.Empty; 
      for (int i = 0; i < m_chatLines.Count; i++) 
      { 
       ret += m_chatLines[i] + "<br>"; 
      } 
      return ret; 
     } 

     public void Add(string line) 
     { 
      m_chatLines.Insert(0, line); 
      if (m_chatLines.Count > m_maxLines) 
      { 
       m_chatLines.RemoveAt(m_chatLines.Count - 1); 
      } 
     } 
    } 
} 

測試aspx文件

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="CometTest.Default" %> 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 

<html xmlns="http://www.w3.org/1999/xhtml"> 
<head runat="server"> 
    <title></title> 
</head> 
<body> 
    <form id="form1" runat="server"> 

     <asp:ScriptManager ID="ScriptManager1" runat="server"> 
      <Services> 
       <asp:ServiceReference Path="~/Chat.asmx" /> 
      </Services> 
     </asp:ScriptManager> 

     <div id="lyrChatLines" style="height: 200px; width: 300px; border: 1px solid #cccccc; overflow: scroll"> 
     </div> 

     <asp:Panel runat="server" DefaultButton="cmdSend"> 
      <asp:UpdatePanel runat="server"> 
       <ContentTemplate> 
        <asp:TextBox style="width: 220px" runat="server" ID="txtChat"></asp:TextBox> 
        <asp:Button runat="server" ID="cmdSend" Text="Send" OnClick="cmdSend_Click" /> 
       </ContentTemplate> 
      </asp:UpdatePanel> 
     </asp:Panel> 

     <script type="text/javascript"> 

      function CometReceive() 
      { 
       CometTest.Chat.ReceiveChat_Comet(receive, commError, commError); 
      } 

      function ReceiveNow() 
      { 
       CometTest.Chat.ReceiveChat(receive, commError, commError); 
      } 

      function receive(str) 
      { 
       document.getElementById("lyrChatLines").innerHTML = str; 
       setTimeout("CometReceive()", 0); 
      } 

      function commError() 
      { 
       document.getElementById("lyrChatLines").innerHTML = 
        "Communication Error..."; 
       setTimeout("CometReceive()", 5000); 
      } 

      setTimeout("ReceiveNow()", 0); 
     </script> 
    </form> 
</body> 
</html> 

背後

的ASPX代碼
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.UI; 
using System.Web.UI.WebControls; 

namespace CometTest 
{ 
    public partial class Default : System.Web.UI.Page 
    { 
     protected void Page_Load(object sender, EventArgs e) 
     { 

     } 

     protected void cmdSend_Click(object sender, EventArgs e) 
     { 
      Chat service = new Chat(); 
      service.Send 
      (
       Request.UserHostAddress + "> " + 
       txtChat.Text 
      ); 
      txtChat.Text = string.Empty; 
      txtChat.Focus(); 
     } 
    } 
} 

如果任何人有事業一個好的理論和/或修復的看似隨意的崩潰會如果you'ld後:)

回答

1

這個問題.NET Comet engine有一些鏈接,應指向您在大加讚賞正確的方向。您需要查看實現IHttpAsyncHandler來處理長時間運行的彗星請求。

+0

謝謝!我會盡快嘗試。我有一個http處理程序,我寫了解決這個問題,但我實現了IHttpHandler(不是asnyc),所以我會definatley試一試。你認爲有可能在不創建HTTP處理程序的情況下做到這一點?我問,因爲開發一個簡單的lib可以很容易地用在像上面這樣的web servie中。 –

+1

我沒有使用網絡服務,所以我不能說。然而,我使用IHttpAsyncHandler開發了一個彗星服務器,並且它工作得很好。 IIS/http.sys使用固定數量的線程來處理傳入的請求,如果您將它們與長時間運行或阻塞(.WaitOne)調用綁定在一起,可以很快地殺死iis。 –

+0

這是從msdn幫助http://msdn.microsoft.com/en-us/library/aa480516.aspx鏈接?它討論了異步Web方法。 –