英文:
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 ---> 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<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<Microsoft.AspNetCore.Connections.ConnectionContext>:SetException (System.Exception)
Microsoft.AspNetCore.Http.Connections.Client.HttpConnectionFactory/<ConnectAsync>d__3:MoveNext ()
System.Runtime.CompilerServices.AsyncTaskMethodBuilder:SetException (System.Exception)
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection/<StartAsync>d__40:MoveNext ()
System.Runtime.CompilerServices.AsyncTaskMethodBuilder:SetException (System.Exception)
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection/<StartAsyncCore>d__41:MoveNext ()
System.Runtime.CompilerServices.AsyncTaskMethodBuilder:SetException (System.Exception)
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection/<SelectAndStartTransport>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<Microsoft.AspNetCore.Http.Connections.NegotiationResponse>:SetException (System.Exception)
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection/<NegotiateAsync>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<System.Net.Http.HttpResponseMessage>:SetException (System.Exception)
Microsoft.AspNetCore.Http.Connections.Client.Internal.AccessTokenHttpMessageHandler/<SendAsync>d__3:MoveNext ()
System.Threading.Tasks.TaskFactory`1<System.Net.WebResponse>:FromAsyncCoreLogic (System.IAsyncR
Code:<br>
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;
}
答案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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论