用户何时离开聊天页面(通过注销或仅通过简单关闭浏览器窗口)。聊天脚本立即检测到该用户离开并显示脱机签名。这个过程会在几秒钟后发生,这是如何真正起作用的?
我是ASP.NET / c#开发人员,除此之外我使用JavaScripts而很少使用PHP。请不要超过其他语言的答案。
答案 0 :(得分:6)
正如所承诺的,这里有一些用于实现长轮询的类。基本上有6个类(见下文)。为了您的目的,其中一些类可能最终不需要,但它们对我来说是有道理的。这些“大部分”已经为您消毒了。
如果您需要有关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
}
}
答案 1 :(得分:5)
让您的JavaScript聊天代码使用XMLHttpRequest每2秒向服务器发送一条消息。当您没有收到消息时,这意味着用户已关闭窗口。
答案 2 :(得分:1)
聊天可以使用onunload
事件发送注销消息,如果用户离开页面/关闭浏览器,则会触发该消息,但这不可靠。服务器的第二个选项是在基础TCP连接关闭后立即开始超时倒计时,并在用户未及时重新连接时将其显示为“离线”。