SignalR 연결을 어떻게 종료 할 수 있습니까?


10

SignalR을 사용하여 웹 사이트에서 데이터를 전송하고 있습니다. 그러나 SignalR은 일정 기간 동안 만 데이터를 전송할 수 있어야하며, 시간이 경과하면 연결이 끊어 져야합니다.

$.connection.hub.stop()요청이 여전히 보류 중이고 완료되지 않으면 중지 기능 이 취소됩니다. 그러나이 요청은 전송 된 데이터 양에 관계없이 취소해야합니다.

SignalR-Connection을 어떻게 죽일 수 있습니까?

답변:


6

Microsoft 설명서에서 시간 초과 및 연결 유지 설정에 대한 내용을 확인할 수 있습니다 연결 유지 옵션에서 DisconnectTimeout을 정의 할 수 있습니다.

예:

protected void Application_Start(object sender, EventArgs e)
{
    // Make long-polling connections wait a maximum of 110 seconds for a
    // response. When that time expires, trigger a timeout command and
    // make the client reconnect.
    GlobalHost.Configuration.ConnectionTimeout = TimeSpan.FromSeconds(110);

    // Wait a maximum of 30 seconds after a transport connection is lost
    // before raising the Disconnected event to terminate the SignalR connection.
    GlobalHost.Configuration.DisconnectTimeout = TimeSpan.FromSeconds(30);

    // For transports other than long polling, send a keepalive packet every
    // 10 seconds. 
    // This value must be no more than 1/3 of the DisconnectTimeout value.
    GlobalHost.Configuration.KeepAlive = TimeSpan.FromSeconds(10);

    RouteTable.Routes.MapHubs();
}

편집 : 클라이언트와의 연결을 CancellationToken끊고 싶기 때문에 동작 에 대해 이야기하고 있지만 불행히도 여기여기 에서 볼 수 있듯이 SignalR에서는 여전히 지원되지 않지만 팀은이를 원 SignalR하지만 여전히 있습니다. 그것에 대해 뉴스가 없습니다.


내가 말했듯이 프론트 엔드 사이트의 요청이 완료되지 않았으므로 여전히 프론트 엔드의 일부 데이터가 SignalR-Backend / Hub로 전송됩니다. 따라서 적절한 양의 데이터가 전송되어 일정 기간이 경과하면 데이터 전송 여부에 관계없이 프런트 엔드에서 연결을 종료해야하기 때문에 프론트 엔드 솔루션을 찾고 있습니다. 내가 찾고있는 것을 이해합니까?
Snickbrack

@Snickbrack 지금 데이터를 보내더라도 클라이언트 측을 통해 연결을 끊고 싶습니다.
Kiril1512

1
예. 당신이 올바른지.
Snickbrack

@Snickbrack이 내 답변을 업데이트했습니다.
Kiril1512

@Snickbrack은 귀하의 질문에 대한 정답을 선택하는 것을 잊지 마세요, 여기 또는 다른 답변은 여기에 있습니다 ...
Kiril1512

1

허브 수명 이벤트에 대한 Microsoft 문서를 읽으십시오 . 이러한 설정의 기본값을 변경하고 파일 Application_Start에서 설정할 수 Global.asax있습니다. 그러나 이렇게하면 클라이언트 측을 완전히 제어 할 수 없습니다. 그래서 당신은 자바 스크립트 setTimeout기능 을 사용 하고 새로운 사용자가 connect.it 일 때 GlobalHost.Configuration.DisconnectTimeout또는 원하는 시간이 되면 시간 양식 서버 끝을 전달합니다 . 데모 프로젝트로 전체 예제를 제공합니다. 실제로 실시간 보류 티켓을 위해 매우 큰 티켓 시스템에서이 논리를 사용합니다.(모든 인라인 주석을 읽으십시오)

모델:

public class MyModel
{
    public int Id { get; set; }

    public string Name { get; set; }


    public static string Send(MyModel my)
    {
        //Do Somthing           
        return $"Data Sending to {my.Name}...";
    }
    public static string Stop(string name)
    {
        //Do Somthing

        return $"ForceStop {name}.";
    }
    public static string Delete()
    {
        //Do Somthing

        return "Deleted";
    }
}

바퀴통:

[HubName("myHub")]
public class MyHub : Hub
{
    int connectionTimeOut = 10;//sec

    [HubMethodName("connect")]
    public void Connect()
    {  
            //apply logic if any when user connected or reload page
            //set connection Time Out as you need
        connectionTimeOut= 10;// GlobalHost.Configuration.DisconnectTimeout

       Clients.Client(Context.ConnectionId).onNewUserConnected(connectionTimeOut);
    }
    [HubMethodName("startSendingServer")]
    public void StartSending(int id, string name)//pass anything you need
    {
        //apply logic if any when start sending data

        var my = new MyModel
        {
            Id = id,
            Name = name
        };
        var status = MyModel.Send(my);//example

        var result = new
        {
            status,
            name
        };

        Clients.Client(Context.ConnectionId).startSendingClient(result);

    }

    [HubMethodName("forceStopServer")]
    public void ForceStop(string name)//pass anything you need
    {
        //apply logic if any when force stop sending data
        var status = MyModel.Stop(name);
        Clients.Client(Context.ConnectionId).forceStopClint(status);
    }


    public override Task OnDisconnected(bool stopCalled)
    {

        //apply logic if any when connection Disconnected

        var status = MyModel.Delete();//example
        if (stopCalled)
        {
            //  status=String.Format("Client {0} explicitly closed the connection.", Context.ConnectionId)
            //your code here
        }
        else
        {
            // status=String.Format("Client {0} timed out .", Context.ConnectionId);
            //your code here
            //Clients.Client(Context.ConnectionId).onUserDisconnected(status);
        }

        return base.OnDisconnected(stopCalled);
    }


}

TestView :

<div class="row">
    <div class="col-md-12">
        <h1> Status: <span id="hubStatus"></span></h1>
        <br />
        <h4> Countdown : <span id="counter"></span></h4>
        <br />

        <button id="btnHub" class="btn btn-primary btn-lg">Start Sending Data</button>
    </div>
</div>
@section scripts{
    <script src="~/Scripts/app/hub.js"></script>
}

hub.js :

var proxyTimer = null;
var sendTimeLimit = 1;//sec
var sessionTime = sendTimeLimit * 1000;

$(function () {
    var myProxy = $.connection.myHub;
    $.connection.hub.start().done(function () {
        registerServerEvents(myProxy);
    });

    clientMethods(myProxy);
});

function registerServerEvents(proxyHub) {
    proxyHub.server.connect();
    $(document).on("click", "#btnHub", function (e) {

        $("#hubStatus").html("Sending..");
        $("#btnHub").text("Count Down Start...");

        //Logic Before start sending data.
        var id = 1;
        var name = "AzR";        
        proxyHub.server.startSendingServer(id,name);

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

        $.connection.hub.disconnected(function () {
            $("#hubStatus").html("Disconnected");// you can restart on here.     
            $("#btnHub").text("Stat Again after reload window");

        });

    });
}



function clientMethods(proxyHub) {

    //proxyHub.on('onConnected', function (sendTimeLimit) {
    //    sendTimeLimit = sendTimeLimit;
    //});

    proxyHub.on('onNewUserConnected', function (serverItem) {
        sendTimeLimit = serverItem;
        sessionTime = sendTimeLimit * 1000;
    });


    proxyHub.on('startSendingClient', function (serverItem) {

        //Logic after start sending data.
        var name = serverItem.name;
        var status = serverItem.status;
        $("#hubStatus").html(status);
        $("#counter").html(sendTimeLimit);
        timeCounter();
        startTimer(proxyHub, name );
    });

    proxyHub.on('forceStopClint', function (serverItem) {


        clearClintPendingTask(serverItem);//Logic before proxy stop.
        $("#btnHub").text("Force Stop...");
        $.connection.hub.stop();
    });

    proxyHub.on('onUserDisconnected', function (serverItem) {
        //Logic after proxy Disconnected (time out).
        $("#hubStatus").html(serverItem);
        $("#btnHub").text("Stat Again after reload window");
   });
}

//Logic before proxy stop.
function clearClintPendingTask(status) {
    //do all you need
    $("#hubStatus").html(status); 
    stopTimer();
}

function startTimer(proxyHub,data) {
    stopTimer();
    proxyTimer = setTimeout(function () {
        proxyHub.server.forceStopServer(data);
    }, sessionTime);
}

function stopTimer() {
    if (proxyTimer) {
        clearTimeout(proxyTimer);
        proxyTimer = null;
    }
}

function timeCounter() {
    var counter = sendTimeLimit;
    var interval = setInterval(function () {
        counter--;
        $("#counter").html(counter);
        if (counter == 0) {
            //Do something
            $("#counter").html("Countdown ended!");
            // Stop the counter
            clearInterval(interval);
        }
    }, 1000);
}

(테스트)


0

시간 초과를 정의해야합니다. 서버에서 다음과 같이 DisconnectTimeout을 설정할 수 있습니다.

GlobalHost.Configuration.DisconnectTimeout = TimeSpan.FromMinutes(30);

https://zzz.buzz/2016/05/11/setting-timeout-for-signalr-for-easier-debugging/


내가 말했듯이 프론트 엔드 사이트의 요청이 완료되지 않았으므로 여전히 프론트 엔드의 일부 데이터가 SignalR-Backend / Hub로 전송됩니다. 그래서 나는 프론트 엔드 솔루션을 찾고 있습니다.
Snickbrack

0

업데이트 된 편집, 아래 옵션 3을 참조하십시오 .다른 모든 사람들은 시간 초과에 의존하고 있습니다. 강제 연결을 해제했습니다.

강제 연결 해제를 시도하는 경우 연결된 사용자 목록을 가져 와서 ForceLogOut 서버 측 함수를 . 코드 프로젝트 에서이 부분을 보았을 때 도움이되기를 바랍니다. 일부 사용자 만 강제 로그 아웃 / 킬 (kill)하려는 경우 해당 연결 만 반복하여 종료하십시오.

서버 측


public class User
{
    public string Name { get; set; }
    public HashSet<string> ConnectionIds { get; set; }
}

public class ExtendedHub : Hub
{        
   private static readonly ConcurrentDictionary<string, User> ActiveUsers  = 
      new ConcurrentDictionary<string, User>(StringComparer.InvariantCultureIgnoreCase);
    public IEnumerable<string> GetConnectedUsers()
    {
        return ActiveUsers.Where(x => {

            lock (x.Value.ConnectionIds)
            {
                return !x.Value.ConnectionIds.Contains
                        (Context.ConnectionId, StringComparer.InvariantCultureIgnoreCase);
            }

        }).Select(x => x.Key);
    }           

    public void forceLogOut(string to)
    {
        User receiver;
        if (ActiveUsers.TryGetValue(to, out receiver))
        {
            IEnumerable<string> allReceivers;
            lock (receiver.ConnectionIds)
            {
                allReceivers = receiver.ConnectionIds.Concat(receiver.ConnectionIds);      
            }

            foreach (var cid in allReceivers)
            {
             // ***************** log out/KILL connection for whom ever your want here
                Clients.Client(cid).Signout();
            }
        }
    }
}

고객 입장에서

 // 1- Save your connection variable when you start it, and later on you can use it to stop.
var myHubProxy = $.connection.myHub 
// 2- Use it when you need to stop it, IF NOT YOU WILL GET AN ERROR
myHubProxy.client.stopClient = function() {
    $.connection.hub.stop();
};

// With a button for testing
$('#SomeButtonKillSignalr').click(function () {
            $.connection.hub.stop();                
        });

옵션 3으로 업데이트 : 요청에 따라 ... 다른 솔루션은 시간 초과에 의존하지만 직접 연결을 배치하여 직접 적용 할 수도 있습니다

SignalR 코드를 열면 내부 DisposeAndRemoveAsync에서 클라이언트 연결이 실제로 종료 된 것을 볼 수 있습니다 .

1- DisposeAndRemoveAsync연결을 수정하거나 전화 를 걸 수 있습니다 .

2- 그런 다음 전화 RemoveConnection(connection.ConnectionId);

public async Task DisposeAndRemoveAsync(HttpConnectionContext connection)
        {
            try
            {
                // this will force it
                await connection.DisposeAsync();
            }
            catch (IOException ex)
            {
                _logger.ConnectionReset(connection.ConnectionId, ex);
            }
            catch (WebSocketException ex) when (ex.InnerException is IOException)
            {
                _logger.ConnectionReset(connection.ConnectionId, ex);
            }
            catch (Exception ex)
            {
                _logger.FailedDispose(connection.ConnectionId, ex);
            }
            finally
            {
                // Remove it from the list after disposal so that's it's easy to see
                // connections that might be in a hung state via the connections list
                RemoveConnection(connection.ConnectionId);
            }
        }

주의 :이 작업이 완료되면 스스로 청소하십시오.


내가 언급했듯이 $.connection.hub.stop()-Function은 요청이 백엔드로 완전히 전송되지 않아 오류를 발생시킵니다. 따라서 실행중인 요청이 있어도 현재 활성 연결을 종료하는 솔루션을 찾고 있습니다.
Snickbrack
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.