十年網(wǎng)站開(kāi)發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營(yíng)維護(hù)+專業(yè)推廣+無(wú)憂售后,網(wǎng)站問(wèn)題一站解決
在網(wǎng)上搜了搜,沒(méi)有發(fā)現(xiàn)C#實(shí)現(xiàn)http長(zhǎng)連接的開(kāi)源項(xiàng)目,估計(jì)是實(shí)現(xiàn)起來(lái)太簡(jiǎn)單了吧。自己寫(xiě)一個(gè),不是項(xiàng)目中使用,純粹測(cè)試一下。
創(chuàng)新互聯(lián)公司是一家朝氣蓬勃的網(wǎng)站建設(shè)公司。公司專注于為企業(yè)提供信息化建設(shè)解決方案。從事網(wǎng)站開(kāi)發(fā),網(wǎng)站制作,網(wǎng)站設(shè)計(jì),網(wǎng)站模板,微信公眾號(hào)開(kāi)發(fā),軟件開(kāi)發(fā),成都小程序開(kāi)發(fā),十載建站對(duì)建筑動(dòng)畫(huà)等多個(gè)領(lǐng)域,擁有豐富的網(wǎng)站推廣經(jīng)驗(yàn)。
1、原理
所謂長(zhǎng)連接,是指客戶端以http協(xié)議連接到服務(wù)器,區(qū)別于一般的短連接,服務(wù)器不會(huì)立即返回?cái)?shù)據(jù),而是保持住這個(gè)連接,等到有數(shù)據(jù)時(shí)才返回。說(shuō)起來(lái)簡(jiǎn)單,但卻不能使用Sleep或者信號(hào)量的方式保持住連接,因?yàn)檫@么做會(huì)長(zhǎng)時(shí)間占用線程,客戶端多時(shí)很快會(huì)占滿ASP.Net的線程池。
ASP.Net提供了IHttpAsyncHandler接口,允許開(kāi)發(fā)者以異步方式處理http請(qǐng)求。示意圖如下:

Http請(qǐng)求到達(dá)服務(wù)器后,被BeginProce***equest方法處理,它個(gè)方法要生成一個(gè)IAsyncResult對(duì)象,并將其保存到其它地方,之后返回。此時(shí)連接將保持住,但ASP.Net已經(jīng)可以空出資源去處理下一個(gè)請(qǐng)求了。直到程序的業(yè)務(wù)邏輯觸發(fā)IAsyncResult對(duì)象的Callback,IHttpAsyncHandler對(duì)象的EndProce***equest方法才被調(diào)用,此時(shí)可以做輸出,之后這個(gè)http請(qǐng)求才真正結(jié)束。
2、IHttpAsyncHandler實(shí)現(xiàn)
using System;
using System.Web;
namespace Comet
{
public class CometAsyncHandler : IHttpAsyncHandler
{
///
/// 請(qǐng)求到達(dá)時(shí)的處理方法
///
public IAsyncResult BeginProce***equest(HttpContext context, AsyncCallback callback, object extraData)
{
//通過(guò)context可以取請(qǐng)求附加的數(shù)據(jù),略
//...
//之后生成IAsyncResult對(duì)象,callback比較重要,調(diào)用這個(gè)回調(diào),EndProce***equest才被觸發(fā)
var result = new CometResult(context, callback, extraData);
//在返回之前把剛生成的IAsyncResult對(duì)象保存起來(lái),略
//...
return result;
}
///
/// 請(qǐng)求結(jié)束時(shí)的處理方法
///
public void EndProce***equest(IAsyncResult asyncResult)
{
//得到對(duì)應(yīng)的IAsyncResult對(duì)象
var result = asyncResult as CometResult;
//后續(xù)處理,如輸出內(nèi)容等,略
//...
}
public bool IsReusable
{
get { return false; }
}
public void Proce***equest(HttpContext context)
{
throw new NotImplementedException();
}
}
}3、IAsyncResult實(shí)現(xiàn)
using System;
using System.Web;
using System.Threading;
namespace Comet
{
public class CometResult : IAsyncResult
{
#region 實(shí)現(xiàn)IAsyncResult接口
public object AsyncState { get; private set; }
public WaitHandle AsyncWaitHandle { get; private set; }
public bool CompletedSynchronously { get; private set; }
public bool IsCompleted { get; private set; }
#endregion
public AsyncCallback Callback { get; private set; }
public HttpContext Context { get; private set; }
public object ExtraData { get; private set; }
public CometResult(HttpContext context, AsyncCallback callback, object extraData)
{
this.Context = context;
this.Callback = callback;
this.ExtraData = extraData;
}
public Call()
{
if(this.Callback != null)
this.Callback(this);
}
}
}4、調(diào)用
找到對(duì)應(yīng)的IAsyncResult對(duì)象,調(diào)用其Call方法即可。
5、配置文件
在
考慮到兼容IIS7,還要在
6、針對(duì)MVC的特殊處理
增加HttpHandler會(huì)受mvc影響,需要在RegisterRoutes方法里加忽略:
//忽略Data.aspx
routes.IgnoreRoute("Data.aspx/{*pathInfo}");搞定收工,請(qǐng)求Data.aspx時(shí),連接會(huì)被保持住,直到通過(guò)另一個(gè)頁(yè)面調(diào)用IAsyncResult對(duì)象的Call方法,當(dāng)前連接才會(huì)返回。
簡(jiǎn)單測(cè)試了一下,保持3000個(gè)連接很輕松,并且都能快速響應(yīng),達(dá)到了預(yù)期。由于.net有默認(rèn)最大并發(fā)連接數(shù)的限制,客戶端如果開(kāi)多個(gè)連接,需要把 ServicePointManager.DefaultConnectionLimit 調(diào)大一些。另外開(kāi)到1300多個(gè)連接的時(shí)候就報(bào)OutOfMemoryException了,所以要多用幾臺(tái)客戶端測(cè)。