2011-06-20 10 views
5

Sto facendo il mio primo tentativo di sperimentare con Comet. Ho sviluppato una semplice web app di chat - fondamentalmente un mondo di cometa ciao via C#. Il problema che sto riscontrando è che a volte IIS si blocca e per errore intendo semplicemente smettere di rispondere alle richieste HTTP. Quindi, richiede sempre il riavvio del pool di app e talvolta dell'intero servizio IIS. Sono quasi sicuro che il colpevole sia l'oggetto ManualResetEvent che sto usando per bloccare i thread di richieste di cometa fino a quando non viene ricevuto un segnale per rilasciare (aggiornare) quei thread. Ho provato a scrivere un gestore HTTP per aggirare questo e impostare la proprietà riutilizzabile su false (per inserire nuovi thread di richieste su un'altra istanza dell'oggetto ManualResetEvent) ma ciò non ha funzionato. Sto anche provando ad implementare IRegisteredObject in modo da poter liberare quei thead quando l'app si sta spegnendo, ma sembra che non funzioni neanche. Si blocca ancora e non sembra esserci alcun motivo quando si blocca (che ho notato). Sono quasi sicuro che sia una combinazione di istanze statiche e l'uso di ManualResetEvent che lo sta causando. Non so per certo come o come risolverlo.C# comet server freezing IIS

Comet.cs (Il mio semplice lib cometa)

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

La mia classe di chat e web service

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

Il file di prova 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> 

E il codice aspx dietro

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

Se qualcuno ha una buona teoria sulla causa e/o fissare per il crash apparentemente arbitrari che sarebbe molto apprezzato se you'ld posta :)

risposta

1

Questa domanda .NET Comet engine ha alcuni collegamenti che dovrebbe puntare nella giusta direzione. È necessario considerare l'implementazione di IHttpAsyncHandler per gestire la richiesta cometa a lungo termine.

+0

Grazie! Darò una prova il prima possibile. Ho un gestore http che ho scritto per ovviare a questo problema, ma ho implementato IHHttpHandler (non l'asnyc), quindi cercherò di provarlo. Pensi che sia possibile farlo senza creare un gestore HTTP? Chiedo perché sarebbe bello sviluppare una semplice libreria che possa essere facilmente utilizzata in un servizio web come ho sopra. –

+1

Non ho usato un servizio web, quindi non posso dire. Ho comunque sviluppato un server comet usando IHttpAsyncHandler e funziona alla grande. IIS/http.sys utilizza un numero fisso di thread per elaborare le richieste in arrivo, se li leghi con long run o blocking (.WaitOne) ti chiamano kill rapidamente iis. –

+0

Questo http://msdn.microsoft.com/en-us/library/aa480516.aspx link dalla guida di msdn? Parla Async WebMthods. –