您好,登錄后才能下訂單哦!
在網(wǎng)上搜了搜,沒有發(fā)現(xiàn)C#實現(xiàn)http長連接的開源項目,估計是實現(xiàn)起來太簡單了吧。自己寫一個,不是項目中使用,純粹測試一下。
1、原理
所謂長連接,是指客戶端以http協(xié)議連接到服務(wù)器,區(qū)別于一般的短連接,服務(wù)器不會立即返回數(shù)據(jù),而是保持住這個連接,等到有數(shù)據(jù)時才返回。說起來簡單,但卻不能使用Sleep或者信號量的方式保持住連接,因為這么做會長時間占用線程,客戶端多時很快會占滿ASP.Net的線程池。
ASP.Net提供了IHttpAsyncHandler接口,允許開發(fā)者以異步方式處理http請求。示意圖如下:
Http請求到達服務(wù)器后,被BeginProce***equest方法處理,它個方法要生成一個IAsyncResult對象,并將其保存到其它地方,之后返回。此時連接將保持住,但ASP.Net已經(jīng)可以空出資源去處理下一個請求了。直到程序的業(yè)務(wù)邏輯觸發(fā)IAsyncResult對象的Callback,IHttpAsyncHandler對象的EndProce***equest方法才被調(diào)用,此時可以做輸出,之后這個http請求才真正結(jié)束。
2、IHttpAsyncHandler實現(xiàn)
using System; using System.Web; namespace Comet { public class CometAsyncHandler : IHttpAsyncHandler { /// <summary> /// 請求到達時的處理方法 /// </summary> public IAsyncResult BeginProce***equest(HttpContext context, AsyncCallback callback, object extraData) { //通過context可以取請求附加的數(shù)據(jù),略 //... //之后生成IAsyncResult對象,callback比較重要,調(diào)用這個回調(diào),EndProce***equest才被觸發(fā) var result = new CometResult(context, callback, extraData); //在返回之前把剛生成的IAsyncResult對象保存起來,略 //... return result; } /// <summary> /// 請求結(jié)束時的處理方法 /// </summary> public void EndProce***equest(IAsyncResult asyncResult) { //得到對應(yīng)的IAsyncResult對象 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實現(xiàn)
using System; using System.Web; using System.Threading; namespace Comet { public class CometResult : IAsyncResult { #region 實現(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)用
找到對應(yīng)的IAsyncResult對象,調(diào)用其Call方法即可。
5、配置文件
在<system.web>節(jié)中注冊httpHandler,增加:
<system.web> <httpHandlers> <!-- 針對GET與POST兩種請求,路徑是Data.aspx文件,使用CometAsyncHandler處理 --> <add verb="GET,POST" path="Data.aspx" type="Comet.CometAsyncHandler, Comet"/> </httpHandlers> </system.web>
考慮到兼容IIS7,還要在<system.webServer>節(jié)中注冊,增加:
<system.webServer> <!--忽略system.web中的注冊--> <validation validateIntegratedModeConfiguration="false"/> <modules runAllManagedModulesForAllRequests="true"/> <handlers> <!--與上面完全相同--> <add name="CometHandler" verb="GET,POST" path="Data.aspx" type="Comet.CometAsyncHandler, Comet" /> </handlers> </system.webServer>
6、針對MVC的特殊處理
增加HttpHandler會受mvc影響,需要在RegisterRoutes方法里加忽略:
//忽略Data.aspx routes.IgnoreRoute("Data.aspx/{*pathInfo}");
搞定收工,請求Data.aspx時,連接會被保持住,直到通過另一個頁面調(diào)用IAsyncResult對象的Call方法,當(dāng)前連接才會返回。
簡單測試了一下,保持3000個連接很輕松,并且都能快速響應(yīng),達到了預(yù)期。由于.net有默認最大并發(fā)連接數(shù)的限制,客戶端如果開多個連接,需要把 ServicePointManager.DefaultConnectionLimit 調(diào)大一些。另外開到1300多個連接的時候就報OutOfMemoryException了,所以要多用幾臺客戶端測。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。