【问题标题】:SignalR Does not auto-reconnectSignalR 不会自动重新连接
【发布时间】:2015-11-27 00:13:20
【问题描述】:

我有一个 SignalR Hub 和一个 .net Xamarin Android 客户端。 当使用稳定的互联网连接时,它们工作正常,客户端可以发送到集线器,集线器可以发送到客户端。

但是,客户端似乎无法自动重新连接(与在线文档所说的相反),并且由于以下问题,尝试自己实现重新连接是不可能的。

如果客户端成功启动 HubConnection,状态会从 Disconnected -> Connecting -> Connected。但是,如果您从客户端拔出网线,则它无法到达服务器。状态永远不会(我的意思是永远不会)从“已连接”改变。

我确实收到了一个“ConnectionSlow”事件,但连接状态永远不会改变,并且在连接上调用 Start 什么都不做,因为查看 signalR 源代码,它在内部检查状态是否!=“已连接”,如果不是,它只是返回。 SignalR Github Source Code

我的问题是,您的意思是如何建立与服务器的 SignalR 连接并让它(或实现)自动重新连接。因为我没有尝试过。

【问题讨论】:

  • 我在 Android/ios 应用程序中使用信号器。在这两种情况下,当我禁用 wifi/3g 时,连接都会进入断开状态。不知道为什么这对你不起作用。您是否使用 https 连接到服务器?也许不相关,但当我进行更改时,SSE 开始工作
  • @Kyro 你找到解决方案了吗?我正在处理类似的事情。我对 iOS 有完全相同的体验。一些安卓设备工作了几次然后就停止工作了。
  • @Garrett Daniel DeMeyer 不,我们从未找到解决方案。 SignalR 开发团队认为这不是问题。所以我们放弃了 SignalR,转而使用 XSockets.Net,它们的帮助更大(甚至让我们成为了一个自定义客户端),而且老实说,它们的框架比相当可悲的 signalR 框架要好得多。

标签: xamarin signalr signalr.client


【解决方案1】:

我不确定这是否会对您有所帮助,但请注意:

  1. 在信号器断开连接(即:网络断开连接)后,我发现最好创建一个新的连接集线器。不要期望信号器总是重新连接(它会尝试几秒钟,然后再见连接)。

  2. 如果您想关闭当前连接,请不要尝试关闭它(signalR 可能会在它实际释放连接之前冻结大约 20 秒。只需将连接变量重新分配为一个新变量即可。

这是我的工作代码:

    private async Task Connect(bool dismissCurrentConnection = false)
    {
        // Always create a new connection to avoid SignalR close event delays
        if (connection != null)
        {
            if (!dismissCurrentConnection)
            {
                return;
            }

            connection.StateChanged -= OnConnectionStateChangedHandler;
            connection.Reconnected -= OnReconnectedHandler;
            // DON´T call connection.Dispose() or it may block for 20 seconds
            connection = null;
            proxy = null;
        }

        connection = new HubConnection(Settings.SERVER);
        // connection.TransportConnectTimeout = TimeSpan.FromSeconds(5);
        connection.TraceWriter = tracer;
        connection.TraceLevel = TraceLevels.All;
        connection.StateChanged += OnConnectionStateChangedHandler;
        connection.Reconnected += OnReconnectedHandler;

        proxy = connection.CreateHubProxy("ChatHub");
        proxy.On<ChatMessage>("AddNewMessage", message => AddNewMessage(message));
        proxy.On<ChatMessage>("ConfirmMessageDelivered", Message => ConfirmMessageDelivered(Message));
        proxy.On<string>("ConfirmMessageReceived", uid => ConfirmMessageReceived(uid));
        proxy.On<string>("ConfirmMessageRead", uid => ConfirmMessageRead(uid));
        proxy.On<UserChatStatus>("ChangeUserChatStatus", status => ChangeUserChatStatus(status));

        if (connection.State == ConnectionState.Disconnected)
        {
            try
            {
                MvxTrace.Trace("[{0}] Connecting...", nameof(ChatService));
                await connection.Start();
                await invokeQueue.ProcessQueue();
            }
            catch (Exception ex)
            {
                MvxTrace.Error("[{0}] CONNECTION START ERROR: {1}", nameof(ChatService), ex.Message);
            }
        }
    }

第一次连接时我会用 await Connect(); 后续连接将使用 await Connect(true) 关闭当前连接

    private void OnReconnectedHandler()
    {
        Task.Factory.StartNew(async () => await invokeQueue.ProcessQueue());
    }

    private void OnConnectionStateChangedHandler(StateChange change)
    {
        this.ConnectionState = change.NewState;
        OnConnectionStateChanged?.Invoke(change);

        switch (change.NewState)
        {
            case ConnectionState.Disconnected:
                // SignalR doesn´t do anything after disconnected state, so we need to manually reconnect
                reconnectTokenSource = new CancellationTokenSource();
                Task.Factory.StartNew(async () =>
                {
                    await Task.Delay(TimeSpan.FromSeconds(Settings.RECONNECT_PERIOD_SECONDS), reconnectTokenSource.Token);
                    await Connect(true);
                }, reconnectTokenSource.Token);

                break;
        }
    }

如果您想知道什么是“invokeQueue”,它只是一个自定义实用程序,可在未连接状态时捕获所有信号器代理调用,并在连接恢复后处理它们。

“reconnectTokenSource”将被取消,以防我不希望重新连接过程继续进行(即:关闭活动时)。

看起来我们都有非常相似的配置。唯一明显的区别是您在 Android 项目中使用 nuget,而我在 PCL 上使用它。

在此日志中,您可以检查断开连接事件:

mvx:Diagnostic: 14,72 [SignalRTracer] 01:47:56.2406950 - null - ChangeState(Disconnected, Connecting)
mvx:Diagnostic: 15,48 [SignalRTracer] 01:47:57.0176730 - 6dd879af-7d49-4632-96b2-cb5fb542dc24 - SSE: GET http://192.168.0.53/signalr/connect?clientProtocol=1.4&transport=serverSentEvents&connectionData=[{"Name":"ChatHub"}]&connectionToken=IgMS6rxmjHJCeudFlDRV8jFSt9Tz1Mt210X21RbiFAIalj%2BioMMRWPH5%2BfNaNIkVW%2BzHbv%2FmSjk8uoRNVbK%2FKUL%2FI87iBkejKkXYivq5FZy6x8E1%2FAK2rBnCg3Zi9nwY&noCache=d4878c0b-5c2a-4535-929c-29952f5e6795
mvx:Diagnostic: 15,56 [SignalRTracer] 01:47:57.0945740 - 6dd879af-7d49-4632-96b2-cb5fb542dc24 - SSE: OnMessage(Data: initialized)
mvx:Diagnostic: 15,57 [SignalRTracer] 01:47:57.1054290 - 6dd879af-7d49-4632-96b2-cb5fb542dc24 - SSE: OnMessage(Data: {"C":"d-3050D8AB-B,C|I,0|J,1","S":1,"M":[]})
mvx:Diagnostic: 15,70 [SignalRTracer] 01:47:57.2408050 - 6dd879af-7d49-4632-96b2-cb5fb542dc24 - ChangeState(Connecting, Connected)
mvx:Diagnostic: 15,82 [SignalRTracer] 01:47:57.3586480 - 6dd879af-7d49-4632-96b2-cb5fb542dc24 - SSE: OnMessage(Data: {"C":"d-3050D8AB-B,D|I,0|J,1","M":[]})
mvx:Diagnostic: 15,83 [SignalRTracer] 01:47:57.3718630 - 6dd879af-7d49-4632-96b2-cb5fb542dc24 - OnMessage({"I":"0"})

然后我关闭了wifi:

mvx:Diagnostic: 29,55 [SignalRTracer] 01:48:11.0813880 - 6dd879af-7d49-4632-96b2-cb5fb542dc24 - OnError(System.Net.Sockets.SocketException: Connection timed out at System.Net.Sockets.Socket.EndReceive (IAsyncResult result) [0x0002d] in /Users/builder/data/lanes/2098/3efa14c4/source/mono/mcs/class/System/System.Net.Sockets/Socket.cs:1798 at System.Net.Sockets.NetworkStream.EndRead (IAsyncResult ar) [0x0002f] in /Users/builder/data/lanes/2098/3efa14c4/source/mono/mcs/class/System/System.Net.Sockets/NetworkStream.cs:320 )
mvx:Diagnostic: 31,56 [SignalRTracer] 01:48:13.1037440 - 6dd879af-7d49-4632-96b2-cb5fb542dc24 - ChangeState(Connected, Reconnecting)
mvx:Diagnostic: 31,68 [SignalRTracer] 01:48:13.2199720 - 6dd879af-7d49-4632-96b2-cb5fb542dc24 - OnError(System.Net.Sockets.SocketException: Network is unreachable at System.Net.Sockets.Socket.Connect (System.Net.EndPoint remoteEP) [0x000bc] in /Users/builder/data/lanes/2098/3efa14c4/source/mono/mcs/class/System/System.Net.Sockets/Socket.cs:1235 at System.Net.WebConnection.Connect (System.Net.HttpWebRequest request) [0x0019b] in /Users/builder/data/lanes/2098/3efa14c4/source/mono/mcs/class/System/System.Net/WebConnection.cs:213 )

稍后...

mvx:Diagnostic: 61,68 [SignalRTracer] 01:48:43.2182200 - 6dd879af-7d49-4632-96b2-cb5fb542dc24 - OnError(System.TimeoutException: Couldn't reconnect within the configured timeout of 00:00:30, disconnecting.)
mvx:Diagnostic: 61,69 [SignalRTracer] 01:48:43.2330650 - 6dd879af-7d49-4632-96b2-cb5fb542dc24 - Disconnected
mvx:Diagnostic: 61,76 [SignalRTracer] 01:48:43.2972460 - 6dd879af-7d49-4632-96b2-cb5fb542dc24 - Transport.Dispose(6dd879af-7d49-4632-96b2-cb5fb542dc24)
mvx:Diagnostic: 61,77 [SignalRTracer] 01:48:43.3065810 - 6dd879af-7d49-4632-96b2-cb5fb542dc24 - Closed

【讨论】:

  • 这个问题是连接的状态永远不会从“已连接”改变,它永远不会检测到它已经失去了连接。这真的感觉 SignalR .net 客户端仍处于 alpha 阶段,存在这些基本问题。
  • 您使用的是什么客户端版本?
  • 我在 PCL 项目中使用 2.2.0 版,我可以在 Xamarin 中确认连接状态更改时。你能在你监听连接变化的地方展示你的一些代码吗?
  • 我在 Xamarin Android 项目中安装了 Microsoft.AspNet.SignalR.Client 版本 2.2.0 Nuget 包。至于 State changed 处理程序,它只是一个接受 StateChanged 对象的基本处理程序。它会在连接启动时检测 Connecting->Connected 状态更改。但它永远不会触发 Connected->Disconnected,即使我设置了一个计时器以每分钟运行一次并检查 connection.State 它仍然显示“Connected”。
  • 我认为这是硬件或安卓操作系统的一个更根本的问题。因为一个基本的 System.Net.Sockets.Socket 在蜂窝断开连接时报告自己为已连接(蜂窝由 USB 加密狗提供)。我想看看您的 invokeQueue 实用程序对象的一般设计。
猜你喜欢
  • 2014-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多