0

最近我一直在玩 SignalR,发现它非常适合服务器/客户端通信。

然后我想到了一个与我目前正在从事的项目非常相关的场景。

基本思想是通过 ping 机器在网页上指示服务器当前是否在线。

该过程由第一个访问该页面的用户启动,并应在所有客户端断开连接时停止。

到目前为止,我的服务器代码是这样的:

public class PingHub : Hub
{
    private static readonly ConcurrentDictionary<string, DateTime> _users = new ConcurrentDictionary<string, DateTime>();
    private static bool _isPolling = false;

    public override Task OnConnected()
    {
        _users.TryAdd(Context.ConnectionId, DateTime.Now);

        return Clients.All.UserCountChanged(_users.Count);
    }

    public override Task OnReconnected()
    {
        _users.AddOrUpdate(Context.ConnectionId, DateTime.Now, (key, value) => value);

        return Clients.All.UserCountChanged(_users.Count);
    }

    public override Task OnDisconnected()
    {
        DateTime value;
        _users.TryRemove(Context.ConnectionId, out value);

        return Clients.All.UserCountChanged(_users.Count);
    }

    public void GetStatus()
    {
        if (_isPolling)
            return;

        _isPolling = true;

        var ping = new Ping();
        do
        {
            var reply = ping.Send("X.X.X.X");

            if (reply == null)
            {
                Clients.Caller.SetError(new { error = "No reply!" });
                break;
            }

            Clients.All.SetStatus(new { Status = reply.Status.ToString(), Time = reply.RoundtripTime });

            Thread.Sleep(500);
        } while (_users.Count > 0);

        _isPolling = false;
    }
}

问题是启动进程的用户保持连接,即使浏览器已关闭(我通过记录每个 ping 请求对此进行了测试)。

那么任何人都可以帮助我按预期完成这项工作吗?

4

1 回答 1

8

我最近做了类似的事情。在我的 Global.asax.cs 我有:

private BackgroundProcess bp;
protected void Application_Start( object sender, EventArgs e )
{
    ...
    bp = new BackgroundProcess();
}

然后我有一个BackgroundProcess.cs:

public class BackgroundProcess : IRegisteredObject
{
    private Timer TaskTimer;
    private IHubContext ClientHub;

    public BackgroundProcess()
    {
        HostingEnvironment.RegisterObject( this );

        ClientHub = GlobalHost.ConnectionManager.GetHubContext<webClientHub>();

        TaskTimer = new Timer( OnTimerElapsed, null, TimeSpan.FromSeconds( 0 ), TimeSpan.FromSeconds( 10 ) );
    }

    private void OnTimerElapsed( object sender )
    {
        if (...) //HasAnyClientsConnected, not sure what this would be, I had other criteria
        {
            ClientHub.Clients.All.ping(); //Do your own ping
        }
    }

    public void Stop( bool immediate )
    {
        TaskTimer.Dispose();
        HostingEnvironment.UnregisterObject( this );
    }

这里的关键是 IRegisteredObject。您可以查看它,但 Web 应用程序会在它因任何原因关闭时通知它。

于 2013-04-11T20:17:16.967 回答