温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

ASP.Net实现Http长连接(Comet)

发布时间:2020-08-02 23:13:13 来源:网络 阅读:18460 作者:BoyTNT 栏目:编程语言

   在网上搜了搜,没有发现C#实现http长连接的开源项目,估计是实现起来太简单了吧。自己写一个,不是项目中使用,纯粹测试一下。


1、原理

   所谓长连接,是指客户端以http协议连接到服务器,区别于一般的短连接,服务器不会立即返回数据,而是保持住这个连接,等到有数据时才返回。说起来简单,但却不能使用Sleep或者信号量的方式保持住连接,因为这么做会长时间占用线程,客户端多时很快会占满ASP.Net的线程池。

   ASP.Net提供了IHttpAsyncHandler接口,允许开发者以异步方式处理http请求。示意图如下:

ASP.Net实现Http长连接(Comet)


   Http请求到达服务器后,被BeginProce***equest方法处理,它个方法要生成一个IAsyncResult对象,并将其保存到其它地方,之后返回。此时连接将保持住,但ASP.Net已经可以空出资源去处理下一个请求了。直到程序的业务逻辑触发IAsyncResult对象的Callback,IHttpAsyncHandler对象的EndProce***equest方法才被调用,此时可以做输出,之后这个http请求才真正结束。


2、IHttpAsyncHandler实现

using System;
using System.Web;
namespace Comet
{
    public class CometAsyncHandler : IHttpAsyncHandler
    {
        /// <summary>
        /// 请求到达时的处理方法
        /// </summary>
        public IAsyncResult BeginProce***equest(HttpContext context, AsyncCallback callback, object extraData)
        {
            //通过context可以取请求附加的数据,略
            //...
                                                                                                            
            //之后生成IAsyncResult对象,callback比较重要,调用这个回调,EndProce***equest才被触发
            var result = new CometResult(context, callback, extraData);
            //在返回之前把刚生成的IAsyncResult对象保存起来,略
            //...
            return result;
        }
        /// <summary>
        /// 请求结束时的处理方法
        /// </summary>
        public void EndProce***equest(IAsyncResult asyncResult)
        {
            //得到对应的IAsyncResult对象
            var result = asyncResult as CometResult;
            //后续处理,如输出内容等,略
            //...
        }
        public bool IsReusable
        {
            get { return false; }
        }
        public void Proce***equest(HttpContext context)
        {
            throw new NotImplementedException();
        }
    }
}


3、IAsyncResult实现

using System;
using System.Web;
using System.Threading;
namespace Comet
{
    public class CometResult : IAsyncResult
    {
        #region 实现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、调用

找到对应的IAsyncResult对象,调用其Call方法即可。


5、配置文件

在<system.web>节中注册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>节中注册,增加:

<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时,连接会被保持住,直到通过另一个页面调用IAsyncResult对象的Call方法,当前连接才会返回。

简单测试了一下,保持3000个连接很轻松,并且都能快速响应,达到了预期。由于.net有默认最大并发连接数的限制,客户端如果开多个连接,需要把 ServicePointManager.DefaultConnectionLimit 调大一些。另外开到1300多个连接的时候就报OutOfMemoryException了,所以要多用几台客户端测。




向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI