asp.net 避免 ajax 定時調用,利用 ashx 實現 long polling (長輪詢)

來源:互聯網
上載者:User

動機:朋友跟我說他在公司實現了訊息提醒機制,我問他是怎麼實現的,他說採用定時調用 ajax 的方法來實現。我跟他說我在使用 web qq 時未曾看到系統有定時檢查是否有訊息,但奇怪的是只要一有訊息就能以最快的速度送達給你(從伺服器推送給戶端,不知語義上有沒有說錯,請大家指教)。今天周末,有時間想想簡單地實現這一功能,於是 google 後發現一則 5 分鐘的視頻,很快便瞭解了原理並用 asp.net 實現這一功能(因為那則視頻是用 php 實現的)。

 先附上原視頻地址:http://www.screenr.com/SNH

由於原理簡單,所以直接貼代碼。

ReqHandler.ashx

using System;using System.IO;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.Web;namespace SimpleAjaxLongPolling{    /// <summary>    /// ReqHandler 的摘要說明    /// </summary>    public class ReqHandler : IHttpHandler    {        public void ProcessRequest(HttpContext context)        {            context.Response.ContentType = "text/plain";            string baseDir = "~/Data/";            string fileName = "datasrc.txt";            string filePath = context.Server.MapPath(baseDir + fileName);            /*             * 逾時計數器             */            byte timeoutCount = 0;            /*             * 擷取檔案最後修改時間             */            long otimestamp = File.GetLastWriteTime(filePath).Ticks;            long ctimestamp = File.GetLastWriteTime(filePath).Ticks;            /*             * 擷取上一次送給用戶端的串連反饋中的檔案的最後修改時間,以確定             * 在新的串連到來時,檔案是否有修改過,如果這個參數不為空白,且不             * 為 0(初始值為 0),則說明有過給客戶的串連反饋,就用這個值             * 來作為有無修改的被比較對象。             */            var reqTimeStamp = context.Request.QueryString["ts"];            if (!string.IsNullOrEmpty(reqTimeStamp) && !reqTimeStamp.Equals("0"))            {                otimestamp = Convert.ToInt64(reqTimeStamp);            }            /*             * 核心。如果自上一次串連後,檔案未修改過(即有新的內容),且未超             * 時,此時等待,逾時計數器遞增。             * 迴圈跳出的條件是:檔案有修改(有新的內容)或逾時。             */            while (ctimestamp <= otimestamp && timeoutCount < 30)            {                Thread.Sleep(1000);                ++timeoutCount;                ctimestamp = File.GetLastWriteTime(filePath).Ticks;            }            var outputMsg = String.Empty;            // 迴圈跳出後的操作            if (timeoutCount < 30)            {                /*                 * 如果未逾時,則說明有新的內容                 */                var lines = File.ReadAllLines(filePath);                if (lines.Length > 0)                {                    outputMsg = lines[0];                }            }            var output = string.Format("{{'msg':'{0}', 'timestamp':'{1}'}}", outputMsg, ctimestamp);            context.Response.Write(output);        }        public bool IsReusable        {            get            {                return false;            }        }    }}

  GetMsg.aspx

    <form id="form1" runat="server">    <div id="msg_zone">        <ul id="msg_list">            <li>等待訊息中...</li>        </ul>    </div>    </form>    <script type="text/javascript">        var $msgFmtStr = '<li>%1</li>';        var $timestamp = 0;        var $timer = null;        $(document).ready(function () {            getMsgs();        });        function getMsgs() {            $.ajax({                type: 'GET',                async: true,                cache: false,                url: 'ReqHandler.ashx',                data:{ts:$timestamp},                success: function (data) {                    var $json = eval('(' + data + ')');                    if ($json['msg'] != '') {                        $('ul#msg_list').append($msgFmtStr.replace('%1', $json['msg']));                    }                    $timestamp = $json['timestamp'];                    getMsgs();                },                error: function (XMLHttpRequest, textState, error) {                    $('ul#msg_list').append($msgFmtStr.replace('%1', 'Error:(' + textState + ', ' + error + ')'));                    setTimeout("getMsgs()", 5000);                }            });        }    </script>

  附上 demo :

http://pan.baidu.com/share/link?shareid=541364&uk=657243248

補充:

針對有些園友對My Code提出疑問,我補充以下內容,歡迎大家繼續參與交流,畢竟是第一次認識長串連,也不知道自己瞭解得對不對,希望得到大牛們指點。

首先請看圖:

每一次調用都會發起一次串連,由於得不到伺服器的響應,所以這個串連會一直保持,紅框所示。圖中說明該串連保持了 30 s(因為後台以 30s 作為連線逾時),在這 30s 內,該串連會一直阻塞,但用戶端的操作不會有任何阻塞,直到返回,釋放此次串連,轉而執行下一次串連,也就是說再次調用 getMsgs()。但請注意,getMsgs() 不會一直調用,因為調用他是有條件的,

其一:$(document).ready();

其二:發起的串連得到響應,且 Status 是 OK,則立即調用,如果出現錯誤,則會在 10s 後再次調用該函數。

所以不存在用戶端的 CPU 的佔用會有 100% 的情況,而且伺服器也不會佔用太多 CPU,因為有 Sleep。 

請大家提供更好的解決方案,一起學習,ths!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.