2011-08-31 29 views
3

當用戶離開聊天頁面時(通過註銷或僅通過簡單關閉瀏覽器窗口)。聊天腳本立即檢測到用戶離開並顯示離線標誌。這個過程在幾秒鐘內發生,這真的有效嗎?驗證用戶在聊天腳本中的存在

我是一個ASP.NET/c#開發者,除此之外我使用JavaScripts,很少使用PHP。請不要超過對其他語言的回答。

+1

查找到長輪詢爲好。 –

+0

@Prisoner - 很好的回答!希望它能幫助我。給我一天。我會嘗試。 – Mal

+0

我在 –

回答

5

只需使用XMLHttpRequest,您的JavaScript聊天代碼每2秒向服務器發送一條消息。當您沒有收到消息時,這意味着用戶已關閉窗口。

+0

中添加了一些類來實現長輪詢。'XMLHttpRequest'的工作原理要快得多,以便每2秒驗證一次,並且即使聊天服務器同時裝載了數百萬用戶,它也可能帶有污點嗎? – Mal

1

該聊天可以使用onunload事件發送註銷消息,該事件在用戶離開頁面/關閉瀏覽器時觸發,但它不可靠。服務器的第二個選項是在底層TCP連接關閉後立即開始超時倒計時,並在用戶沒有及時重新連接的情況下將用戶顯示爲「脫機」。

6

按照承諾,這裏有一些類用於實施長期投票。基本上有6類(見下文)。其中一些類可能最終不需要用於您的目的,但它們對我而言是有意義的。這些「大部分」已經爲您消毒。

  1. 控制器:創建一個有效的響應所需工藝操作(分貝操作等)
  2. 處理器:管理非同步通信與網頁(本身)
  3. IAsynchProcessor:服務處理實現此接口的實例
  4. 服務:進程請求實現IAsynchProcessor的對象
  5. 請求:包含您迴應(對象)
  6. 響應的IAsynchProcessor包裝:包含自定義對象或字段

如果需要使用JavaScript幫助或HTML加載評論如下。我會爲你寫點東西。

HTTP處理程序:

using System; 
using System.Configuration; 
using System.Web; 
using System.Web.Script.Serialization; 
using System.Web.Services; 
using System.Web.SessionState; 

namespace Concept.LongPolling.Handlers 
{ 
    /// <summary> 
    /// Summary description for Controller 
    /// </summary> 
    public class Controller : IHttpHandler, IReadOnlySessionState 
    { 
     #region CONSTRUCTORS 
     #endregion 

     #region PROPERTIES 

     /// <summary>Gets a Boolean value indicating that another request can use the current instance of the DefaultHttpHandler class.</summary> 
     /// <remarks>Returning true makes the same AsyncHttpHandler object be used for all requests.</remarks> 
     /// <remarks>Returning false here makes ASP.Net create object per request.</remarks> 
     public bool IsReusable { get { return true; } } 

     #endregion 

     #region METHODS 

     /// <summary>Enables synchronous processing of HTTP Web requests</summary> 
     /// <param name="context">An HttpContext object that provides references to the intrinsic server objects</param> 
     /// /// <remarks>This is where you would send commands to the controller that would affect processing in some manner.</remarks> 
     public void ProcessRequest(HttpContext context) 
     { 
      throw new NotImplementedException(); 
     } 

     /// <summary>Creates the response object which is serialized back to the client</summary> 
     /// <param name="response"></param> 
     public static Response CreateResponse(Response response) 
     { 
      try 
      { 
       response.Generate(); 
      } 
      catch (System.Exception ex) 
      { 
       response.SessionValid = false; 
      } 

      return response; 
     } 

     #endregion 
    } 
} 

using System; 
using System.Configuration; 
using System.Web; 
using System.Web.Script.Serialization; 
using System.Web.Services; 
using System.Web.SessionState; 
using Concept.LongPolling.LongPolling; 

namespace Concept.LongPolling.Handlers 
{ 
    /// <summary> 
    /// Summary description for Processor 
    /// </summary> 
    public class Processor : IHttpHandler, IHttpAsyncHandler, IReadOnlySessionState 
    { 
     #region CONSTRUCTORS 
     #endregion 

     #region PROPERTIES 

     /// <summary>Gets a Boolean value indicating that another request can use the current instance of the DefaultHttpHandler class.</summary> 
     /// <remarks>Returning true makes the same AsyncHttpHandler object be used for all requests.</remarks> 
     /// <remarks>Returning false here makes ASP.Net create object per request.</remarks> 
     public bool IsReusable { get { return false; } } 

     #endregion 

     #region METHODS 

     /// <summary>Enables synchronous processing of HTTP Web requests</summary> 
     /// <param name="context">An HttpContext object that provides references to the intrinsic server objects</param> 
     public void ProcessRequest(HttpContext context) 
     { 
      throw new NotImplementedException(); 
     } 

     #region IHttpAsyncHandler Members 

     /// <summary>Enables asynchronous processing of HTTP Web requests</summary> 
     /// <param name="context">An HttpContext object that provides references to the intrinsic server objects</param> 
     /// <param name="cb">The method to call when the asynchronous method call is complete. If callback is null, the delegate is not called.</param> 
     /// <param name="extraData"></param> 
     /// <returns>Any state data that is needed to process the request.</returns> 
     public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) 
     { 
      Int32 someValueYouLikeToSendInYourClass = Convert.ToInt32(context.Request["Number"]); 

      Request request = new Request(cb, context); 
      request.Response.Number = someValueYouLikeToSendInYourClass; 

      Service.Singleton.AddRequest(request); 

      return request; 
     } 

     /// <summary>Provides an end method for an asynchronous process.</summary> 
     /// <param name="result">An object that contains information about the status of the process.</param> 
     public void EndProcessRequest(IAsyncResult result) 
     { 
      Request request = result as Request; 
      JavaScriptSerializer serializer = new JavaScriptSerializer(); 

      request.HttpContext.Response.ContentType = "text/json"; 
      request.HttpContext.Response.Write(serializer.Serialize(request.Response)); 
      request.HttpContext.Response.End(); 
     } 

     #endregion 

     #endregion 
    } 
} 

支持類:

using System; 
using System.Runtime.InteropServices; 

namespace Concept.LongPolling.LongPolling 
{ 
    /// <summary>Represents the executable instance of an asynchronous operation.</summary> 
    [ComVisible(true)] 
    public interface IAsynchProcessor : IAsyncResult 
    { 
     /// <summary> 
     /// Gets a value that indicates whether the operation completed sucessfully. 
     /// </summary> 
     /// <returns>true if the operation completed sucessfully; otherwise, false.</returns> 
     bool ProcessRequest(); 
    } 
} 


using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Threading; 

namespace Concept.LongPolling.LongPolling 
{ 
    public class Service 
    { 
     #region CONSTRUCTORS 

     private Service() 
     { 
      requests = new List<IAsynchProcessor>(); 
      backgroundThread = new Thread(new ThreadStart(MainLoop)); 
      backgroundThread.IsBackground = true; 
      backgroundThread.Start(); 
     } 

     #endregion 

     #region PROPERTIES 

     static readonly object _padlock = new object(); 

     private static Service singleton; 
     private Thread backgroundThread; 
     private List<IAsynchProcessor> requests; 

     public static Service Singleton 
     { 
      get 
      { 
       lock (_padlock) 
       { 
        if (_singleton == null) 
         _singleton = new Service(); 
        return _singleton; 
       } 
      } 
     } 

     #endregion 

     #region METHODS 

     private void MainLoop() 
     { 
      while (true) 
      { 
       foreach (IAsynchProcessor request in requests.ToArray()) 
       { 
        if (request.ProcessRequest()) 
         requests.Remove(request); 
       } 
       Thread.Sleep(500); 
      } 
     } 

     public void AddRequest(IAsynchProcessor request) 
     { 
      requests.Add(request); 
     } 

     #endregion 
    } 
} 

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using Concept.LongPolling.Business; 
using System.Data; 

namespace Concept.LongPolling.Handlers 
{ 
    public class Response 
    { 
     #region CONSTRUCTORS 

     public Response() 
     { 
      SessionValid = true; 
      Exception = String.Empty; 
     } 

     #endregion 

     #region PROPERTIES 

     public const int TimeOffset = 120; 

     public Int32 Number { get; set; } 
     public bool SessionValid { get; set; } 
     public String Exception { get; set; } 

     #endregion 

     #region METHODS 

     public void Generate() 
     { 
      // do some desired operation 
      Number += 1; 
     } 

     #endregion 
    } 
} 

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using Concept.LongPolling.LongPolling; 

namespace Concept.LongPolling.Handlers 
{ 
    public class Request : IAsynchProcessor 
    { 
     #region CONSTRUCTORS 

     public Request(AsyncCallback callback, HttpContext context) 
     { 
      asyncCallback = callback; 
      httpContext = context; 
      createdTime = DateTime.Now; 

      Response = new Response(); 
     } 

     #endregion 

     #region PROPERTIES 

     public const int TimeoutSeconds = 15; 

     private AsyncCallback asyncCallback; 
     private HttpContext httpContext; 
     private DateTime createdTime; 

     public bool TimedOut 
     { 
      get 
      { 
       return ((DateTime.Now - createdTime).TotalSeconds >= TimeoutSeconds); 
      } 
     } 

     public Response Response { get; set; } 

     #region IAsyncResult Members 

     public HttpContext HttpContext 
     { 
      get 
      { 
       return httpContext; 
      } 
     } 
     public object AsyncState { get; set; } 

     System.Threading.WaitHandle IAsyncResult.AsyncWaitHandle 
     { 
      get { throw new NotImplementedException(); } 
     } 

     bool IAsyncResult.CompletedSynchronously 
     { 
      get { return false; } 
     } 

     public bool IsCompleted 
     { 
      get { return isCompleted; } 
      set 
      { 
       if (!value) return; 

       this.isCompleted = true; 
       asyncCallback(this); 
      } 
     } 
     bool isCompleted = false; 

     #endregion 

     #endregion 

     #region METHODS 

     public bool ProcessRequest() 
     { 
      this.Response = Controller.CreateResponse(this.Response); 
      this.IsCompleted = true; 

      return this.IsCompleted; 
     } 

     #endregion 
    } 
}