ฉันจะฆ่าการเชื่อมต่อ SignalR ได้อย่างไร?


10

ฉันใช้ SignalR เพื่อถ่ายโอนข้อมูลบนเว็บไซต์ แต่ SignalR ควรจะสามารถส่งข้อมูลในช่วงระยะเวลาหนึ่งเท่านั้นและหากช่วงเวลาที่ผ่านการเชื่อมต่อควรถูกฆ่า

ฟังก์ชั่นหยุดทำงาน$.connection.hub.stop()จะถูกยกเลิกหากคำขอยังค้างอยู่และยังไม่เสร็จสมบูรณ์ แต่คำขอนี้ควรถูกบังคับให้ยกเลิกไม่ว่าจะส่งข้อมูลไปเท่าใด

ฉันจะฆ่าการเชื่อมต่อสัญญาณได้อย่างไร

คำตอบ:


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แต่ยังมี ไม่มีข่าวเกี่ยวกับมัน


ตามที่ฉันระบุการร้องขอจาก Frontend-Site ยังไม่เสร็จสิ้นดังนั้นยังมีข้อมูลบางส่วนจาก frontend ที่จะส่งไปยัง SignalR-Backend / Hub ดังนั้นฉันกำลังมองหาโซลูชันส่วนหน้าเพราะมีการส่งข้อมูลในปริมาณที่เหมาะสมและหากผ่านช่วงเวลาหนึ่งไปแล้วการเชื่อมต่อควรถูกทำลายโดยส่วนหน้าไม่ว่าข้อมูลจะถูกส่งหรือไม่ก็ตาม คุณเข้าใจสิ่งที่ฉันกำลังมองหา?
Snickbrack

@Snickbrack คุณต้องการที่จะฆ่าการเชื่อมต่อผ่านทางฝั่งไคลเอ็นต์แม้ว่าคุณจะส่งข้อมูลตอนนี้ใช่ไหม?
Kiril1512

1
ใช่. คุณถูก.
Snickbrack

@Snickbrack อัพเดทคำตอบของฉันแล้ว
Kiril1512

@Snickbrack อย่าลืมเลือกคำตอบที่ถูกต้องสำหรับคำถามของคุณคำตอบนี้หรือคำตอบอื่น ๆ ที่นี่ ...
Kiril1512

1

กรุณาอ่าน เอกสาร microsoft นี้เกี่ยวกับเหตุการณ์ Hub ตลอดชีวิต คุณสามารถเปลี่ยนค่าเริ่มต้นสำหรับการตั้งค่าเหล่านี้ได้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";
    }
}

Hub:

[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/


ตามที่ฉันระบุการร้องขอจาก Frontend-Site ยังไม่เสร็จสิ้นดังนั้นยังมีข้อมูลบางส่วนจาก frontend ที่จะส่งไปยัง SignalR-Backend / Hub ดังนั้นฉันกำลังมองหาวิธีแก้ปัญหาส่วนหน้า
Snickbrack

0

อัปเดตการแก้ไขแล้วโปรดดูตัวเลือก 3ด้านล่าง คนอื่น ๆ ทั้งหมดพึ่งพาการหมดเวลาฉันโพสต์การยกเลิกการเชื่อมต่อแบบบังคับ

หากคุณกำลังพยายามยกเลิกการเชื่อมต่อ - คุณสามารถรับรายชื่อผู้ใช้ที่เชื่อมต่อและโทร ForceLogOutฟังก์ชั่นทางฝั่งเซิร์ฟเวอร์ฉันเห็นสิ่งนี้ในโปรเจคโค้ดฉันหวังว่ามันจะช่วยได้ หากคุณต้องการบังคับให้ออกจากระบบ / ฆ่าผู้ใช้บางคนเพียงแค่วนซ้ำและทำลายการเชื่อมต่อนั้นเท่านั้น

ฝั่งเซิร์ฟเวอร์


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()- ฟังก์ชั่นจะพ่นข้อผิดพลาดเนื่องจากคำขอยังไม่ได้ถูกส่งไปยังแบ็กเอนด์อย่างเต็มที่ ดังนั้นฉันกำลังมองหาวิธีการแก้ปัญหาที่ฆ่าการเชื่อมต่อที่ใช้งานอยู่ในปัจจุบันแม้ว่าจะมีคำขอทำงานอยู่
Snickbrack
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.