Làm thế nào tôi có thể giết kết nối SignalR?


10

Tôi đang sử dụng SignalR để chuyển dữ liệu trên một trang web. Nhưng SignalR chỉ có thể gửi dữ liệu trong một khoảng thời gian và nếu khoảng thời gian đó trôi qua, kết nối sẽ bị hủy.

Chức năng dừng $.connection.hub.stop()bị hủy nếu yêu cầu vẫn đang chờ xử lý và chưa hoàn thành. Nhưng yêu cầu này nên bị buộc phải hủy bỏ cho dù có bao nhiêu dữ liệu đã được gửi.

Làm thế nào tôi có thể giết một SignalR-Connection?

Câu trả lời:


6

Như bạn có thể thấy trong Tài liệu Microsoft này về thời gian chờ và cài đặt cố định, bạn có thể xác định DisconnectTimeout trong các tùy chọn.

Thí dụ:

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();
}

Chỉnh sửa : Vì bạn muốn CancellationTokenhủy kết nối từ máy khách cho dù thế nào, bạn đang nói về một hành vi nhưng thật không may, điều này vẫn không được hỗ trợ trong SignalR như bạn có thể thấy ở đâyở đây , nhóm muốn làm điều đó SignalRnhưng vẫn còn không có tin tức gì về nó


Như tôi đã nói, yêu cầu từ Frontend-Site chưa được hoàn thành nên vẫn còn một số dữ liệu từ frontend được gửi đến SignalR-Backend / Hub. Vì vậy, tôi đang tìm kiếm một giải pháp frontend vì một lượng dữ liệu kha khá được gửi đi và nếu một khoảng thời gian trôi qua thì kết nối sẽ bị hủy bởi frontend bất kể dữ liệu có được truyền đi hay không. Bạn có hiểu những gì tôi đang tìm kiếm?
Snickbrack

@Snickbrack bạn muốn hủy kết nối thông qua phía máy khách, ngay cả khi bạn đang gửi dữ liệu ngay bây giờ, tôi có đúng không?
Kiril1512

1
Đúng. Bạn nói đúng.
Snickbrack

@Snickbrack cập nhật câu trả lời của tôi.
Kiril1512

@Snickbrack đừng quên chọn câu trả lời đúng cho câu hỏi của bạn, câu trả lời này hoặc câu trả lời khác tại đây ...
Kiril1512

1

Vui lòng đọc tài liệu microsoft này về sự kiện trọn đời Hub. Bạn có thể thay đổi các giá trị mặc định cho các cài đặt này, đặt chúng trong tệp Application_Startcủa bạn Global.asax. Nhưng theo cách này bạn không thể kiểm soát hoàn toàn phía khách hàng. Vì vậy, bạn sử dụng setTimeoutchức năng javascript và vượt qua thời gian kết thúc máy chủ biểu mẫu khi người dùng mới kết nối. Nó có thể GlobalHost.Configuration.DisconnectTimeouthoặc bất cứ lúc nào bạn muốn. Tôi đưa ra một ví dụ đầy đủ với dự án demo. Trên thực tế tôi sử dụng logic này trong một hệ thống bán vé rất lớn cho vé giữ thời gian thực. (vui lòng đọc tất cả bình luận nội tuyến)

Mô hình:

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";
    }
}

Trung tâm:

[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);
    }


}

Xem thử:

<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);
}

(Thử nghiệm)


0

Bạn cần xác định thời gian chờ. Trên máy chủ, bạn có thể đặt DisconnectTimeout, như thế này:

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

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


Như tôi đã nói, yêu cầu từ Frontend-Site chưa được hoàn thành nên vẫn còn một số dữ liệu từ frontend được gửi đến SignalR-Backend / Hub. Vì vậy, tôi đang tìm kiếm một giải pháp frontend.
Snickbrack

0

Cập nhật Chỉnh sửa, vui lòng xem Tùy chọn 3 bên dưới. Tất cả những người khác đang dựa vào thời gian chờ, tôi đã đăng một ngắt kết nối bắt buộc.

Nếu bạn đang thử Force Disconnect - bạn có thể lấy danh sách Người dùng được kết nối và gọi ForceLogOutHàm ở phía máy chủ, tôi đã thấy điều này ở đâu đó trong dự án mã, tôi hy vọng nó có ích. Nếu bạn chỉ muốn ForceLogout / giết một số người dùng, chỉ cần lặp qua và giết kết nối đó mà thôi.

Phía máy chủ


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();
            }
        }
    }
}

Phía khách hàng

 // 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();                
        });

Được cập nhật với Tùy chọn 3 : dựa trên yêu cầu ... các giải pháp khác dựa vào thời gian chờ, nhưng bạn cũng có thể buộc nó trực tiếp bằng cách tự hủy kết nối

Tôi đã mở mã SignalR và bên trong bạn có thể thấy DisposeAndRemoveAsyncsự chấm dứt thực sự của kết nối máy khách.

1- Bạn có thể sửa đổi hoặc gọi DisposeAndRemoveAsyncvới kết nối của bạn.

2- Sau đó gọi 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);
            }
        }

Chú ý, làm bất kỳ việc làm sạch bản thân khi điều này được thực hiện.


Như tôi đã nói, $.connection.hub.stop()-Chức năng ném lỗi vì yêu cầu chưa được gửi đầy đủ đến Phần cuối. Vì vậy, tôi đang tìm kiếm một giải pháp giết chết kết nối hiện đang hoạt động ngay cả khi có yêu cầu đang chạy.
Snickbrack
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.