Unity + SignalR – HttpRequestException results in frame drop

huangapple go评论71阅读模式
英文:

Unity + SignalR - HttpRequestException results in frame drop

问题

以下是您要翻译的代码部分:

The workflow:
我启动服务器,将客户端连接到服务器,然后关闭服务器。

What happens in the code:
因此,在断开连接后,WithAutomaticReconnect 中定义的行为将被执行,然后连接将关闭。

关闭后,我想建立一个新的连接。因此,我通过调用我的操作从 Closed 方法重新启动连接。StartAsync 导致 HttpRequestException,这是预期的,因为服务器仍然离线。在这里发生的奇怪的事情是,一旦发生这种情况,我的应用程序(在HoloLens上)的FPS从60FPS下降到10FPS。它保持在那个低水平大约20秒,然后再次上升到60FPS。发生了什么?

Error:

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

Code:

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;
}
英文:

I have a server (asp.core-web-api-project) and a client (Unity/HoloLens). The connection works fine under normal circumstances. However, I wanted to see what happens in case of a disconnect and what I can do to reconnect.

The workflow:<br>
I start the server, connect the client to it and close the server.

What happens in the code:<br>
So, after disconnecting, the defined behaviour in WithAutomaticReconnect gets executed and then the connection gets closed.

After the closure I want to establish a new connection. Therefore I restart the connection from the method Closed by invoking my action. StartAsync results in a HttpRequestException and is working as expected, because the server is still offline. The strange thing here is that as soon as this happens, the FPS of my application (on the HoloLens) drops from 60FPS to 10FPS. It stays maybe 20 seconds that low and then rises up again to 60FPS. What is happening here?

Error:<br>

Default: ⨯[SignalRClient]: System.Net.Http.HttpRequestException: An error occurred while sending the request ---&gt; System.Net.WebException: Error: ConnectFailure (No connection could be established because the target computer refused to connect.
UnityEngine.DebugLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[])
MyLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[]) (at Assets/Scripts/Logging/MyLogHandler.cs:29)
UnityEngine.Logger:LogError (string,object)
MyApp.Logging.MyLogger:DoLog (MyApp.Logging.DebugMode,System.Action`2&lt;string, object&gt;,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/&lt;StartConnection&gt;d__4:MoveNext () (at Assets/Scripts/Clients/SignalRClient.cs:78)
System.Runtime.CompilerServices.AsyncTaskMethodBuilder:SetException (System.Exception)
Microsoft.AspNetCore.SignalR.Client.HubConnection/&lt;StartAsync&gt;d__48:MoveNext ()
System.Runtime.CompilerServices.AsyncTaskMethodBuilder:SetException (System.Exception)
Microsoft.AspNetCore.SignalR.Client.HubConnection/&lt;StartAsyncInner&gt;d__49:MoveNext ()
System.Runtime.CompilerServices.AsyncTaskMethodBuilder:SetException (System.Exception)
Microsoft.AspNetCore.SignalR.Client.HubConnection/&lt;StartAsyncCore&gt;d__58:MoveNext ()
System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder`1&lt;Microsoft.AspNetCore.Connections.ConnectionContext&gt;:SetException (System.Exception)
Microsoft.AspNetCore.Http.Connections.Client.HttpConnectionFactory/&lt;ConnectAsync&gt;d__3:MoveNext ()
System.Runtime.CompilerServices.AsyncTaskMethodBuilder:SetException (System.Exception)
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection/&lt;StartAsync&gt;d__40:MoveNext ()
System.Runtime.CompilerServices.AsyncTaskMethodBuilder:SetException (System.Exception)
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection/&lt;StartAsyncCore&gt;d__41:MoveNext ()
System.Runtime.CompilerServices.AsyncTaskMethodBuilder:SetException (System.Exception)
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection/&lt;SelectAndStartTransport&gt;d__44:MoveNext ()
System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1&lt;Microsoft.AspNetCore.Http.Connections.NegotiationResponse&gt;:SetException (System.Exception)
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection/&lt;GetNegotiationResponseAsync&gt;d__52:MoveNext ()
System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1&lt;Microsoft.AspNetCore.Http.Connections.NegotiationResponse&gt;:SetException (System.Exception)
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection/&lt;NegotiateAsync&gt;d__45:MoveNext ()
System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1&lt;System.Net.Http.HttpResponseMessage&gt;:SetException (System.Exception)
Microsoft.AspNetCore.Http.Connections.Client.Internal.LoggingHttpMessageHandler/&lt;SendAsync&gt;d__2:MoveNext ()
System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1&lt;System.Net.Http.HttpResponseMessage&gt;:SetException (System.Exception)
Microsoft.AspNetCore.Http.Connections.Client.Internal.AccessTokenHttpMessageHandler/&lt;SendAsync&gt;d__3:MoveNext ()
System.Threading.Tasks.TaskFactory`1&lt;System.Net.WebResponse&gt;:FromAsyncCoreLogic (System.IAsyncR

Code:<br>

public class SignalRClient
{
private Action _connectionClosed;
public SignalRClient()
{
_connectionClosed += Restart;
_hubConnection = new HubConnectionBuilder()
.WithUrl(ConfigModel.Config.MyUri + &quot;/hmdHub&quot;)
.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()
=&gt; _ = 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&lt;Alarm&gt;(&quot;CreateAlarm&quot;, (alarmObject) =&gt;
{
MyLogger.Log(DebugMode.Default, &quot;SignalRClient&gt;CreateAlarm&quot;, $&quot;Got new alarm with id: {alarmObject.Id} with message: {alarmObject.Message}&quot;);
});
}
private async Task&lt;bool&gt; StartConnection()
{
_tokenSource = new CancellationTokenSource();
while (true)
{
try
{
await _hubConnection.StartAsync(_tokenSource.Token);
MyLogger.LogSuccess(DebugMode.Default, this, &quot;Connected to SignalR-Hub&quot;);
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, &quot;Attempting to reconnect...&quot;);
return Task.CompletedTask;
}
private Task Reconnected(string arg)
{
MyLogger.LogSuccess(DebugMode.Default, this, &quot;Connection restored.&quot;);
return Task.CompletedTask;
}
private Task Closed(Exception arg)
{
MyLogger.LogWarning(DebugMode.Default, this, &quot;Connection closed.&quot;);
_connectionClosed?.Invoke();
return Task.CompletedTask;
}
private HubConnection _hubConnection;
private CancellationTokenSource _tokenSource;
}

答案1

得分: 1

The method WithAutomaticReconnect could either take a TimeSpan array, or a RetryPolicy.

If you use WithAutomaticReconnect, there's no point in manually calling the StartConnection method. SignalR will take care of that reconnection for you, trying as many times as objects you have in your array (if you don't want an infinite loop), or infinitely by using a custom RetryPolicy.

You can create a custom IRetryPolicy in order to achieve that.

英文:

The method WithAutomaticReconnect could either take a TimeSpan array, or a RetryPolicy.

If you use WithAutomaticReconnect, there's no point in manually calling the StartConnection method. SignalR will take care of that reconnection for you, trying as many times as objects you have in your array (if you don't want an infinite loop), or infinitely by using a custom RetryPolicy.

You can create a custom IRetryPolicy in order to achieve that.

huangapple
  • 本文由 发表于 2023年3月3日 22:39:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/75628442.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定