ProgramingTip

SignalR 2.0 .NET 클라이언트를 서버 허브에 다시 연결하는 모범 사례

bestdevel 2020. 10. 19. 12:21
반응형

SignalR 2.0 .NET 클라이언트를 서버 허브에 다시 연결하는 모범 사례


다양한 유형의 연결 해제를 처리해야하는 모바일 애플리케이션에서 .NET 클라이언트와 함께 SignalR 2.0을 사용하고 있습니다. SignalR 클라이언트가 자동으로 다시 연결되는 경우, 다시 호출 HubConnection.Start()하여 직접 다시 연결해야하는 경우에 있습니다 .

SignalR이 가끔 마법처럼 자동으로 다시 연결되기 때문에 기능 또는 구성 설정이 필요합니다.

자동으로 다시 연결되는 클라이언트를 설정하는 가장 좋은 방법은 무엇입니까?


Closed()이벤트 를 처리하고 n 초 후에 연결 하는 자바 펼쳐보기를 보았습니다 . 권장되는 접근 방식이 있습니까?

내가 읽은 문서 와 SignalR 연결의 수명에 대한 여러 기사를,하지만 난 여전히 클라이언트 재 연결을 처리하는 방법에 대한 불분명 해요.


나는 마침내 발견했다. 이 질문을 이후로 배운 내용은 다음과 같습니다.

배경 : Xamarin / Monotouch 및 .NET SignalR 2.0.3 클라이언트를 사용하여 iOS 앱을 빌드하고 있습니다. 우리는 기본 SignalR 프로토콜을 사용하고 소켓 웹 소켓 대신 SSE를 사용하는 것입니다. Xamarin / Monotouch에서 웹 소켓을 사용할 수 있는지 아직 확실하지 않습니다. 모든 것은 Azure 웹 사이트를 사용하여 호스팅됩니다.

SignalR 서버에 빠르게 다시 연결하는 앱이 필요했지만 연결이 자체적으로 다시 연결되지 않고 다시 연결하는 데 정확히 30 초가 계속 문제가 계속 발생했습니다 (기본 프로토콜 초과로 인해).

테스트를 마친 세 가지 시나리오가 있습니다.

시나리오 A- 앱이 처음 될 때 연결. 이 첫날부터 완벽하게 작동했습니다. 연결은 3G 모바일 연결 완료 0.25 초 내 완료됩니다. (이미 라디오가 풍부한 가정)

시나리오 B- 앱이 30 초 동안 유휴 / 닫힌 후 SignalR 서버에 다시 연결됩니다. 이 시나리오에서 SignalR은 결국에는 특별한 작업없이 자체적으로 서버에 다시 연결하여 다시 연결을 시도하기 전에 클라이언트 30 초 동안 대기하는 것처럼 보입니다. (앱에 비해 너무 느림)

이 30 초의 대기 기간 동안 동안 효과가 없었습니다. HubConnection.Start () 호출을 시도했습니다. HubConnection.Stop () 호출도 30 초가입니다. SignalR에서 해결 된 사이트 것으로 보이는 관련 버그를 발견 했지만 v2.0.3에서도 여전히 동일한 문제가 발생합니다.

시나리오 C- 앱이 120 초 이상 유휴 / 닫힌 후 SignalR 서버에 다시 연결됩니다. 이 시나리오에서는 SignalR 전송 프로토콜이 이미 시간 초과되었는데 클라이언트가 자동으로 다시 연결되지 않았습니다. 이 클라이언트가 가끔씩 만 재 연결되는 이유를 설명합니다. 좋은 소식은 HubConnection.Start () 호출이 시나리오 거의 거의 즉시한다는 것입니다.

그래서 앱이 30 초 동안 닫혔는지 120 초 이상으로 닫혔는지에 따라 재 연결 조건이 다르다는 것은 데 시간이 걸렸습니다. SignalR 추적 로그가 기본 프로토콜에서 진행되는 작업을 조명하지만 코드에서 전송 수준 이벤트를 처리하는 방법이 생각합니다. (Closed () 이벤트는 시나리오 B에서 30 초 후, 시나리오 C에서 즉시 발생합니다. 상태 속성은 재 연결 대기 기간 동안 "연결됨"으로 표시되고 다른 관련 이벤트 나 메서드는 없음)

해결 방법은 분명합니다. SignalR이 재 연결 마법을 수행하기를 기다리지 않습니다. 대신 앱이 생성되는 휴대 전화의 네트워크 연결이 될 때 이벤트를 정리하고 HubConnection을 참조 해제합니다 (30 초가 걸리지 않습니다. 이제 모든 것이 잘 작동합니다. 어떤 새로운 인스턴스를 만드는 대신 지속 연결을 시작하고 다시 연결해야 생각했습니다.


연결이 긴 이벤트에 타이머를 설정하여 자동으로 다시 연결을 시도하는 것이 내가 아는 유일한 방법입니다.

자바 펼쳐에서는 다음과 같이 수행합니다.

$.connection.hub.disconnected(function() {
   setTimeout(function() {
       $.connection.hub.start();
   }, 5000); // Restart connection after 5 seconds.
});

이 문서에서 권장되는 접근 방식입니다.

http://www.asp.net/signalr/overview/signalr-20/hubs-api/handling-connection-lifetime-events#clientdisconnect


.NET 클라이언트를 요구하는 OP 이후 (아래의 winform 구현),

private async Task<bool> ConnectToSignalRServer()
{
    bool connected = false;
    try
    {
        Connection = new HubConnection("server url");
        Hub = Connection.CreateHubProxy("MyHub");
        await Connection.Start();

        //See @Oran Dennison's comment on @KingOfHypocrites's answer
        if (Connection.State == ConnectionState.Connected)
        {
            connected = true;
            Connection.Closed += Connection_Closed;
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Error: {ex.Message}");
    }
    return connected;
}

private async void Connection_Closed()
{   // A global variable being set in "Form_closing" event 
    // of Form, check if form not closed explicitly to prevent a possible deadlock.
    if(!IsFormClosed) 
    {
        // specify a retry duration
        TimeSpan retryDuration = TimeSpan.FromSeconds(30);
        DateTime retryTill = DateTime.UtcNow.Add(retryDuration);

        while (DateTime.UtcNow < retryTill)
        {
            bool connected = await ConnectToSignalRServer();
            if (connected)
                return;
        }
        Console.WriteLine("Connection closed")
    }
}

매직 재 연결 문제를 방지하기 위해 재 연결 상태가 시작되기 전에 안드로이드에서 서버 메소드를 호출 할 수 있습니다.

SignalR 허브 C #

 public class MyHub : Hub
    {
        public void Ping()
        {
            //ping for android long polling
        }
 }

Android에서

private final int PING_INTERVAL = 10 * 1000;

private boolean isConnected = false;
private HubConnection connection;
private ClientTransport transport;
private HubProxy hubProxy;

private Handler handler = new Handler();
private Runnable ping = new Runnable() {
    @Override
    public void run() {
        if (isConnected) {
            hubProxy.invoke("ping");
            handler.postDelayed(ping, PING_INTERVAL);
        }
    }
};

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    System.setProperty("http.keepAlive", "false");

    .....
    .....

    connection.connected(new Runnable() {
        @Override
        public void run() {
            System.out.println("Connected");
            handler.postDelayed(ping, PING_INTERVAL);
    });
}

참고 URL : https://stackoverflow.com/questions/23375043/best-practice-for-reconnecting-signalr-2-0-net-client-to-server-hub

반응형