Unity + SignalR - HttpRequestException 导致丢帧

问题描述 投票:0回答:1

我有一个服务器(ASP.NET Core Web API 项目)和一个客户端(Unity/HoloLens)。正常情况下连接工作正常。但是,我想看看断开连接时会发生什么以及如何重新连接。

工作流程

我启动服务器,将客户端连接到它并关闭服务器。

代码中发生了什么

断开连接后,

WithAutomaticReconnect
中定义的行为被执行,然后连接被关闭。

关闭后我想建立一个新的连接。因此,我通过调用我的操作从方法

Closed
重新启动连接。
StartAsync
结果为
HttpRequestException
并且按预期工作,因为服务器仍处于离线状态。奇怪的是,一旦发生这种情况,我的应用程序(在 HoloLens 上)的 FPS 就会从 60FPS 下降到 10FPS。它会在这个低水平停留大约 20 秒,然后再次升至 60FPS。这里发生了什么?

错误

默认:⨯[SignalRClient]:System.Net.Http.HttpRequestException:发送请求时发生错误
System.Net.WebException:错误:ConnectFailure(无法建立连接,因为目标计算机拒绝连接。

UnityEngine.DebugLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[])
MyLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[])(位于 Assets/Scripts/Logging/MyLogHandler.cs:29)
UnityEngine.Logger:LogError(字符串,对象)
MyApp.Logging.MyLogger:DoLog (MyApp.Logging.DebugMode,System.Action

2<string, object>,string,object,object[]) (at Assets/Scripts/Logging/MyLogger.cs:66)   MyApp.Logging.MyLogger:LogError (MyApp.Logging.DebugMode,object,object[]) (at Assets/Scripts/Logging/MyLogger.cs:33)   SignalRClient/<StartConnection>d__4:MoveNext () (at Assets/Scripts/Clients/SignalRClient.cs:78)   System.Runtime.CompilerServices.AsyncTaskMethodBuilder:SetException (System.Exception)   Microsoft.AspNetCore.SignalR.Client.HubConnection/<StartAsync>d__48:MoveNext ()   System.Runtime.CompilerServices.AsyncTaskMethodBuilder:SetException (System.Exception)   Microsoft.AspNetCore.SignalR.Client.HubConnection/<StartAsyncInner>d__49:MoveNext ()   System.Runtime.CompilerServices.AsyncTaskMethodBuilder:SetException (System.Exception)   Microsoft.AspNetCore.SignalR.Client.HubConnection/<StartAsyncCore>d__58:MoveNext ()   System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder
1:SetException (System.Exception)
Microsoft.AspNetCore.Http.Connections.Client.HttpConnectionFactory/d__3:MoveNext ()
System.Runtime.CompilerServices.AsyncTaskMethodBuilder:SetException(System.Exception)
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection/d__40:MoveNext ()
System.Runtime.CompilerServices.AsyncTaskMethodBuilder:SetException(System.Exception)
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection/d__41:MoveNext ()
System.Runtime.CompilerServices.AsyncTaskMethodBuilder:SetException(System.Exception) Microsoft.AspNetCore.Http.Connections.Client.HttpConnection/d__44:MoveNext () System.Runtime.CompilerServices.AsyncTaskMethodBuilder
1<Microsoft.AspNetCore.Http.Connections.NegotiationResponse>:SetException (System.Exception) Microsoft.AspNetCore.Http.Connections.Client.HttpConnection/<GetNegotiationResponseAsync>d__52:MoveNext () System.Runtime.CompilerServices.AsyncTaskMethodBuilder
1:SetException(System.Exception) Microsoft.AspNetCore.Http.Connections.Client.HttpConnection/d__45:MoveNext () System.Runtime.CompilerServices.AsyncTaskMethodBuilder
1<System.Net.Http.HttpResponseMessage>:SetException (System.Exception) Microsoft.AspNetCore.Http.Connections.Client.Internal.LoggingHttpMessageHandler/<SendAsync>d__2:MoveNext () System.Runtime.CompilerServices.AsyncTaskMethodBuilder
1:SetException(System.Exception) Microsoft.AspNetCore.Http.Connections.Client.Internal.AccessTokenHttpMessageHandler/d__3:MoveNext () System.Threading.Tasks.TaskFactory`1:FromAsyncCoreLogic(System.IAsyncR

代码:

public class SignalRClient
{
    private Action _connectionClosed;

    public SignalRClient()
    {
        _connectionClosed += Restart;

        _hubConnection = new HubConnectionBuilder()
            .WithUrl(ConfigModel.Config.MyUri + "/hmdHub")
            .WithAutomaticReconnect(new[]{ TimeSpan.FromSeconds(5) })
            .Build();

        _hubConnection.Reconnecting += Reconnecting;
        _hubConnection.Reconnected += Reconnected;
        _hubConnection.Closed += Closed;
    }

    public async void Start()
    {
        ConfigureConnection();
        _ = await StartConnection();
    }

    public async void Restart()
        => _ = await StartConnection();

    public async Task Dispose()
    {
        _connectionClosed -= Restart;

        _hubConnection.Reconnecting -= Reconnecting;
        _hubConnection.Reconnected -= Reconnected;
        _hubConnection.Closed -= Closed;

        await _hubConnection.StopAsync();
        await _hubConnection.DisposeAsync();
    }

    private void ConfigureConnection()
    {
        _hubConnection.On<Alarm>("CreateAlarm", (alarmObject) =>
        {
            MyLogger.Log(DebugMode.Default, "SignalRClient>CreateAlarm", $"Got new alarm with id: {alarmObject.Id} with message: {alarmObject.Message}");
        });
    }

    private async Task<bool> StartConnection()
    {
        _tokenSource = new CancellationTokenSource();

        while (true)
        {
            try
            {
                await _hubConnection.StartAsync(_tokenSource.Token);
                MyLogger.LogSuccess(DebugMode.Default, this, "Connected to SignalR-Hub");
                return true;
            }
            catch when (_tokenSource.IsCancellationRequested)
            {
                return false;
            }
            catch(Exception ex)
            {
                MyLogger.LogError(DebugMode.Default, this, ex.ToString());
                await Task.Delay(5000);
            }
        }
    }

    private Task Reconnecting(Exception arg)
    {
        MyLogger.Log(DebugMode.Default, this, "Attempting to reconnect...");
        return Task.CompletedTask;
    }

    private Task Reconnected(string arg)
    {
        MyLogger.LogSuccess(DebugMode.Default, this, "Connection restored.");
        return Task.CompletedTask;
    }

    private Task Closed(Exception arg)
    {
        MyLogger.LogWarning(DebugMode.Default, this, "Connection closed.");
        _connectionClosed?.Invoke();
        return Task.CompletedTask;
    }

    private HubConnection _hubConnection;
    private CancellationTokenSource _tokenSource;
}
asp.net-core unity-game-engine signalr augmented-reality hololens
1个回答
1
投票

方法

WithAutomaticReconnect
可以采用
TimeSpan
数组,或
RetryPolicy

如果您使用

WithAutomaticReconnect
,则手动调用
StartConnection
方法是没有意义的。 SignalR 将为您处理重新连接,尝试与数组中的对象一样多的次数(如果您不想要无限循环),或者通过使用自定义 RetryPolicy 无限次尝试。

您可以创建自定义 IRetryPolicy 来实现这一目标。

© www.soinside.com 2019 - 2024. All rights reserved.