2011-06-20 6 views
5

Estoy haciendo mi primer intento de experimentar con Comet. Desarrollé una aplicación web de chat muy simple, básicamente, un mundo de cometas a través de C#. El problema que estoy teniendo es que a veces IIS falla y, por accidente, quiero decir que simplemente deja de responder a las solicitudes HTTP. Luego, siempre es necesario reiniciar el grupo de aplicaciones y, a veces, todo el servicio IIS. Estoy casi seguro de que el culpable es el objeto ManualResetEvent que estoy utilizando para bloquear los hilos de solicitudes de cometas hasta que se reciba una señal para liberar (actualizar) esos hilos. Traté de escribir un controlador HTTP para evitar esto y establecer la propiedad reutilizable en falso (para poner nuevos hilos de solicitudes en otra instancia del objeto ManualResetEvent) pero eso no funcionó. También estoy tratando de implementar el IRegisteredObject para que pueda liberar esos theads cuando la aplicación se apaga, pero parece que tampoco funciona. Todavía se cuelga y no parece haber ningún patrón en el momento en que falla (lo he notado). Estoy casi seguro de que es una combinación de instancias estáticas y el uso de ManualResetEvent lo que está causando. Simplemente no sé con certeza cómo o cómo solucionarlo.C# servidor de cometas congelación IIS

Comet.cs (Mi sencilla 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; } 
    } 
} 

Mi clase de chat y servicio 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); 
      } 
     } 
    } 
} 

El archivo aspx prueba

<%@ 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> 

Y el código aspx detrás

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

Si alguien tiene una buena teoría de la causa y/o para fijar los accidentes aparentemente arbitrarias que sería muy apreciada si you'ld posterior :)

Respuesta

1

Esta pregunta .NET Comet engine tiene algunos enlaces que tiene que introducir en el dirección correcta. Debe considerar la implementación de un IHttpAsyncHandler para manejar la solicitud de cometa de larga ejecución.

+0

Gracias! Lo probaré tan pronto como pueda. Tengo un controlador de http que escribí para solucionar este problema, pero implementé IHttpHandler (no el asnyc), así que definitivamente intentaré eso. ¿Crees que es posible hacer esto sin crear un controlador HTTP sin embargo? Lo pregunto porque sería bueno desarrollar una lib simple que se pueda usar fácilmente en un servicio web como el que acabo de mencionar. –

+1

No he usado un servicio web, así que no puedo decirlo. Sin embargo, he desarrollado un servidor de cometas usando el IHttpAsyncHandler y funciona muy bien. IIS/http.sys usa un número fijo de subprocesos para procesar las solicitudes entrantes, si las vincula con llamadas de larga ejecución o de bloqueo (.WaitOne), matará muy rápidamente iis. –

+0

¿Este enlace http://msdn.microsoft.com/en-us/library/aa480516.aspx de msdn ayuda? Habla sobre Async WebMthods. –

Cuestiones relacionadas