【问题标题】:Long polling Stop other request for 1 or 2 minutes长轮询 停止其他请求 1 或 2 分钟
【发布时间】:2012-08-01 06:39:14
【问题描述】:

在创建聊天系统时,我使用 long life request 来获取消息,并使用 jquery 请求来发送消息,如下所示:

*发送:*

$("#btn").click(function () { 
    $.ajax({
        type: "POST",
        url: "Chat.aspx/Insert",
        data: "{ 'Str' :'" + $("#txtStr").val() + "' }",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function (data) {
        },
        error: function () {

        }
    });
});

接收:

function Refresh() {

    $.ajax({
        type: "POST",
        url: "Chat.aspx/GetRecords",
        data: "{ 'Id' : " + $("#hdnV1").val() + "}",
        success: function (data) {

            $.each($(data.d), function () {

               //Show it to user

            });

        },
        complete: function () {
            return Refresh();
        },

        contentType: "application/json; charset=utf-8",
        dataType: "json",
        traditional: true,
        async: true
    });

}

这是我获取消息的服务器端代码:

[WebMethod]
public static object GetRecords(int Id)
{
    TestEntities db = new TestEntities();
    int count = 0;
    while (true)
    {
        if (count++ >= 300)
            return null;


        System.Threading.Thread.Sleep(1000);
        var list = db.Commets.Where(rec => rec.Id > Id).Select(rec => new { Id = rec.Id, Str = rec.Str }).ToList();

        if (list.Count > 0)
            return list;

    }
}

当用户写东西并点击发送按钮时,请求进入挂起状态,我的事情是因为长寿命请求正在执行

我在萤火虫中检查它们,有没有人可以帮助我!?! 更多细节请评论我,对不起我的英语语法不好,我是英语新手

谢谢

【问题讨论】:

  • 我的问题可以理解吗?!!
  • 您是否在应用程序中使用 Session 状态?
  • @user1429080 ,你是什么意思?!是的,我在整个项目中都使用它们!

标签: c# jquery asp.net long-polling


【解决方案1】:

这不是在 asp.net 中建立聊天的最佳方法。随着用户数量的增加,此方法将无法扩展。

看看SignalR 是构建聊天应用程序的好选择。

但是,如果您出于某种原因确实想自己进行,在 asp.net 中构建聊天的最有效方法是使用 IHttpAsyncHandler 和 ajax 请求。

Asp.net 的工作线程数量有限。让其中一个进入睡眠状态只会杀死您的应用程序,即使对于相对较少的用户也是如此。

异步请求允许您延迟请求的响应,直到发生外部事件。
用户调用此处理程序并等待有人向他发送消息。
一旦您将消息发送给用户,它们就会被传递。

客户端收到消息后会发出另一个请求并等待下一条消息。 这就是保持持久连接打开并允许服务器将数据推送到客户端的方式。

这比轮询站点以检查消息是否到达要有效得多。
使用异步处理程序还可以确保在用户等待消息到来时不会浪费任何 asp.net 线程。使用计时器轮询您将很快用完线程来处理 asp.net 中的请求。

这可确保即使网站用户数量增加,您的聊天也能很好地扩展。

这是一个completely working project that implements this,还有 ajax。

避免使用数据库作为您网站上用户之间的通信方式。如果您想记录聊天记录,请进行所有写入异步调用。

【讨论】:

  • 您的回答看起来不错,我正在等待其他人在 6 天内回复,然后将接受最佳答案,感谢您的帮助 :)
  • 不幸的是,使用延迟直到要推送的新信息仍占用请求线程并迅速导致服务器上的线程耗尽的异步控制器操作
【解决方案2】:

由于您在评论中写道您在应用程序中使用Session 状态,因此长时间运行的请求阻止更新可能是正确的。

原因是 Asp.Net 阻止了对Session 的并发访问。有关详细信息,请参阅 MSDN 上的 this link。具体来说(靠近页面底部):

但是,如果对同一会话发出两个并发请求(通过 使用相同的 SessionID 值),第一个请求获得独占 访问会话信息。第二个请求只执行 在第一个请求完成后。

解决此问题的一种方法可能是在相关页面上设置EnableSessionState="ReadOnly"EnableSessionState="False"。这假设您不需要使用聊天系统访问特定页面中的Session

【讨论】:

  • 我会检查并评论结果
【解决方案3】:

您也应该异步发送插入,就像使用 GetRecords 一样。那应该可以解决您的问题。在发送请求中添加async: true

【讨论】:

  • 你的意思是我应该使用 async: true 来发送 ajax 请求?!!
  • 我现在要测试一下你说的内容,给我几分钟时间
  • 我有钢铁这个问题,你的解决方案对我没有帮助,伙计
  • 就像@Chris 所说,您还使用无限循环锁定了服务器。如果您尝试在对数据库的调用之间添加睡眠,它可能会有所帮助。
【解决方案4】:

问题是GetRecords 可能永远不会回来。除非您使用 WebSockets 之类的东西,否则这是一个问题。这意味着连接永远不会完成(直到超时),您很可能不会收到任何数据。

你应该做的是让GetRecords 立即返回,然后每隔 X 秒在你的 jQuery 中轮询新记录。

您还可以尝试在 while 循环中添加Sleep(以及最大循环限制)以允许其他线程在系统中工作并防止无限循环。即

int maxLoops = 50;
int loopNum = 0;
while (loopNum < maxLoops)
{
        var list = db.Commets.Where(rec => rec.Id > Id).Select(rec => new { Id = rec.Id, Str = rec.Str }).ToList();

        if (list.Count > 0)
            return list;

        Thread.Sleep(250); //Wait 1/4 of a second
        loopNum++;
}

【讨论】:

  • 那将是短轮询而不是长轮询,这违背了目的
  • 但是,C# 方法的实现仍然存在缺陷,并且会用 SQL 请求敲击服务器。理想情况下,您希望长轮询器处于某种阻塞状态,或者至少在循环内处于睡眠状态
  • @Chris,我尝试使用 SQL server management studio 插入 int 数据库,GetRecord 将其返回给用户,一切正常
  • 无论哪种方式,问题仍然是 while 循环,也许 Sleep 可能是更好的解决方案?
  • @AliForoughi 通过 SQL 管理工作室做事会很好,我相信 while 循环是你的问题。尝试添加睡眠或添加最大循环限制;查看我的更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-12
相关资源
最近更新 更多