SignalR LongPolling 多个组。为单个客户端添加异常

Posted

技术标签:

【中文标题】SignalR LongPolling 多个组。为单个客户端添加异常【英文标题】:SignalR LongPolling multiple Groups.Add for a single client Exception 【发布时间】:2014-08-03 05:38:32 【问题描述】:

我已经为此苦苦挣扎了一段时间。我们正在使用最新的 SignalR 2.0.3。当我们添加到多个 SignalR 组时,就会出现问题。仅当从具有不同组名的同一 connectionId 发生多个添加时,才会引发异常。如果选择了LOGPOLLING传输,才会抛出异常。仅当您添加 6 个以上的唯一组名(5 个或更少)并且它工作正常时才会引发异常。

这是一个简化的例子:

Index.cshtml

    @model Int32?
    <!DOCTYPE html>
    <head>
        <title></title>
<script src="@Url.Content("~/Scripts/jquery.min.js")" type="text/javascript"/>
<script src="@Url.Content("~/Scripts/jquery.signalR-2.0.3.min.js")"
    type="text/javascript" />
<script src="@Url.Content("~/signalr/hubs")" type="text/javascript"/>
    </head>

    <script>
        _testHub = $.connection.testHub;
        _testHub.client.sayHello = sayHello;
        $.connection.hub.start( transport: 'longPolling' )
            .done(function() 
                addAllGroups();
            );

        function sayHello(aMessage, aGroupName) 
            console.info("GroupName: " + aGroupName 
    + " Message Sent:" + aMessage);
        ;

        function addAllGroups() 
            for (var i = 0; 
              i < @(Model.HasValue ? Model.Value : 1 ); i++) 
                  addToGroupAndBroadcast(i);
            
        ;

        function addToGroupAndBroadcast(aGroupName) 
            _testHub.server.addToGroupAndBroadcast(aGroupName)
                .fail(function (desc) 
                    console.info("Error: " + desc);
                );
        ;

    </script>

SignalRTestController.cs:

using System;
using System.Web.Mvc;


namespace Instrumar.ProductionDashboard.Controllers

    public class SignalRTestController : Controller
    
        #region Public Members

        public ActionResult Index()
        
            return View((int?)Convert.ToInt32(Request.Url.Segments[4]));
        

        #endregion
    

TestHub.cs:

using System.Threading.Tasks;
using Microsoft.AspNet.SignalR;


namespace Instrumar.ProductionDashboard.Hubs

    public class TestHub : Hub
    
        #region Public Members

        public void AddToGroupAndBroadcast(string aGroupName)
        
            GlobalHost.ConnectionManager.GetHubContext<TestHub>().Groups.Add(Context.ConnectionId, aGroupName).Wait();
            Clients.Group(aGroupName).sayHello("Hello", aGroupName);
        

        #endregion
    

Startup.cs:

using Microsoft.AspNet.SignalR;
using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(SignalRChat.Startup))]
namespace SignalRChat


    public class Startup
    
        public void Configuration(IAppBuilder app)
        
            var lHubConfiguration = new HubConfiguration EnableDetailedErrors = true;
            app.UseErrorPage();
            app.MapSignalR(lHubConfiguration);
        
    

控制器将一个整数作为输入,它是要执行的 Add 的数量。例如,如果您调用:

http://yourip.com/WebApplicationName/SignalRTest/Index/1 一个 Groups.Add 工作正常 http://yourip.com/WebApplicationName/SignalRTest/Index/2 两个 Groups.Add 工作正常 http://yourip.com/WebApplicationName/SignalRTest/Index/3 三个 Groups.Add 工作正常 http://yourip.com/WebApplicationName/SignalRTest/Index/4 四个 Groups.Add 工作正常 http://yourip.com/WebApplicationName/SignalRTest/Index/5 五个 Groups.Add 工作正常 http://yourip.com/WebApplicationName/SignalRTest/Index/6六组。添加破碎 http://yourip.com/WebApplicationName/SignalRTest/Index/7七组。添加破碎 http://yourip.com/WebApplicationName/SignalRTest/Index/8八组。添加破碎 http://yourip.com/WebApplicationName/SignalRTest/Index/9九个Groups.Add 破碎 http://yourip.com/WebApplicationName/SignalRTest/Index/10十组。添加破碎

...

当我说损坏时,我在 TestHub.cs 中返回一个“System.Threading.Tasks.TaskCanceledException”,等待任务完成。 ServerSentEvents 一切正常,但 LongPolling 存在问题。我究竟做错了什么?我不能有超过 5 个使用 LongPolling 的 SignalR 组吗?帮我! :)


更新:在客户端调用之间使用 setTimeout 设置 1 毫秒睡眠解决了该问题。这似乎减轻了网络选项卡中待处理连接的数量。当您达到单个浏览器连接限制时,添加到组的能力可能会发生一些事情。很高兴确切地知道为什么这不起作用。

【问题讨论】:

首先,我没有看到您的 VS 版本与您无法升级到开源 SignalR 的最新版本之间的联系。其次,当我实现 SignalR 时,我不需要您发布的任何代码。你从哪里得到你正在使用的代码?你自己写的吗? 谷歌搜索给我的印象是,大于 1.2.1 的 SignalR 版本需要 .net 4.5,而 Visual Studio 2010 不支持。有人提到您可以自己从源代码重建 SignalR,但我们认为这种选择是有风险的。 是的,我自己编写了该代码。这个 js 文件最初要简单得多。我们遵循了 microsoft SignalR 指南,但当我们将软件发布到野外时,我们遇到了问题。由于现实世界的特殊情况,它必须进行修改。我们的软件在一个网站上运行,该网站通过内部网络 24/7 显示,每秒有数百个 signalR 更新。其中一些问题可能是由于我们使用的是旧版本的 SignalR(最初为 1.0.1)造成的,我们可能已经修复了在最新版本的 SignalR 中不再存在错误的问题。 另外,上面 JS 文件中的一些代码是特定于应用程序的。我试图将 JS 文件减少到最低限度,以保持与此问题相关的所有内容。 您可能应该发布更多与您的Service.ClientServices.Registration.Register 方法相关的代码以及将哪些运行时值传递给DashboardHub.Register(String aToken)。您可以主动调试并查看异常还是只是将其登录到文件中?看起来有一个相关问题已在此处修复 github.com/SignalR/SignalR/issues/1155。如果是这样,您将不得不提取代码并重新编译您自己的 DLL。 【参考方案1】:

您可以拥有超过 5 个具有长轮询的组,但您必须通过不循环添加到组来解决连接问题。

Groups.Add 返回的任务只有在收到来自消息总线的 ACK 消息,表明客户端的消息(通知它添加组)已发送时才完成。 如果有超过 5 个(或浏览器强制执行的任何数量)挂起的 AJAX 请求与来自客户端的 addToGroupAndBroadcast 调用相关联,则无法向客户端发送消息。如果您将完成的回调附加到您的客户端调用:

_testHub.server.addToGroupAndBroadcast(groupName).done(function() 
    console.log("complete");
);

您会看到第一个调用几乎立即完成。

这是第一个 Groups.Add 调用返回的时间。发往sayHello 的消息不再发送,因为它需要另一个打开的轮询请求,这是客户端正在创建的,但由于客户端有多个其他挂起的请求已先入队(并且这些都在等待addToGroupAndBroadcast 完成)。

因此,在第一次调用 Groups.Add 后,服务器无法向客户端发送任何内容,MessageHub 无法发送其 ACK,这将解决剩余的 Groups.Add 承诺。 结果,TaskCanceledException 会因为超时而为这些任务抛出。

作为一种变通方法,我建议创建一个接受一组组名的 hub 方法:

public async Task AddToGroups(string[] names)

    foreach (var name in names)
    
        await Groups.Add(Context.ConnectionId, name);
        Clients.Group(name).sayHello("Hello", name);
    

【讨论】:

【参考方案2】:

似乎有一个相关问题已在此处修复https://github.com/SignalR/SignalR/issues/1155。如果是这样,您将不得不提取代码并重新编译您自己的 DLL。此外,您的错误也可能是由超时引起的。

这也可能与您的问题有关:

... 因为您尝试的连接 ID remove 可能不再可用。在这种情况下, 请求超时后抛出TaskCanceledException。

参考。 http://www.asp.net/signalr/overview/signalr-20/hubs-api/working-with-groups

【讨论】:

这似乎是相关的。我们今天刚刚收到 VS 2013,所以我正在使用最新版本的 SignalR 构建针对 .net 4.5 的项目,如果错误得到修复,那么赏金就是你的了。 祝你好运。如果可能的话,我会尽量避免使用异步方法,例如.Wait() 不幸的是,最新版本的 SignalR 2.0.3 和 .net 4.5 仍然可以重现该问题。 所以,一定和你的具体代码有关。关于删除.Wait() 的任何想法?我的实现中没有任何这样的方法。如果实际上您使用的是最新版本,那么您现在是否可以按照最新的文档并“重新创建”您当前的功能?但是,以“推荐”的方式? 我很犹豫是否要按原样删除功能,直到我可以保证我们在现场看到的错误已得到修复。我们必须等待 Groups.Add 的原因是因为有一个后置条件依赖于稍后在注册函数中将客户端添加到组中。它的工作方式是将客户端添加到组中,然后提供初始数据,所有这些都在同一个函数中。我可以用不同的方式重写它,但我宁愿找到这个问题的根源。我已经开始下载 SignalR 源代码,以了解为什么要通过调试器取消任务。

以上是关于SignalR LongPolling 多个组。为单个客户端添加异常的主要内容,如果未能解决你的问题,请参考以下文章

SignalR入门

使用SignalR实现消息提醒

SignalR学习

.net core 3.0 Signalr - 05 使用jwt将用户跟signalr关联

.net core 3.0 Signalr - 05 使用jwt将用户跟signalr关联

signalR 背板是不是也共享连接?