方案如下:如果在短时间内向服务器回调,则认为通信的设备是连接的。 我想创建一个类,它封装了跟踪这种状态的功能。在调用设备时,应重置超时。在回调时,连接已确认,状态应设置为 true ,如果回调超时,则应将其设置为 false 。但是下一次调用应该能够再次无效地重置超时当前状态。
我正在考虑使用swith
和timeout
来实现这一点。但我不知道为什么它会停止工作。
public class ConnectionStatus
{
private Subject<bool> pending = new Subject<bool>();
private Subject<bool> connected = new Subject<bool>();
public bool IsConnected { get; private set; }
public ConnectionStatus(CancellationToken token, short timeoutSeconds = 15)
{
pending.Select(outer => connected.Timeout(TimeSpan.FromSeconds(timeoutSeconds)))
.Switch()
.Subscribe(_ => IsConnected = true, e => IsConnected = false, token);
}
public void ConfirmConnected()
{
connected.OnNext(true);
}
public void SetPending()
{
pending.OnNext(true);
}
}
这是&#34;测试用例&#34;:
var c = new ConnectionStatus(default(CancellationToken));
c.SetPending();
await Task.Delay(TimeSpan.FromSeconds(5));
c.ConfirmConnected();
c.IsConnected.Dump(); // TRUE, OK
c.SetPending();
await Task.Delay(TimeSpan.FromSeconds(5));
c.ConfirmConnected();
c.IsConnected.Dump(); // TRUE, OK
c.SetPending();
await Task.Delay(TimeSpan.FromSeconds(20));
c.IsConnected.Dump(); // FALSE, OK
c.ConfirmConnected();
c.IsConnected.Dump(); // FALSE, OK
c.SetPending();
await Task.Delay(TimeSpan.FromSeconds(10));
c.ConfirmConnected();
c.IsConnected.Dump(); // FALSE, NOT OK!
我假设内部observable的超时也停止了外部的observable。因为outer =>
lambda不再被调用。什么是正确的方法?
谢谢
答案 0 :(得分:3)
问题是Timeout
本质上导致异常炸毁Rx订阅。触发超时后(因为它已编码),将不会发送其他通知。 Rx语法是,您可以有* OnNext
条消息,后跟一个OnCompleted
或一个OnError
。在OnError
发送Timeout
后,您将不会再看到任何消息。
您需要通过OnNext
消息而不是OnError
消息传递超时消息。在旧代码中,您将任何OnError
变为false,将任何OnNext
变为true。相反,您需要将适当的新IsConnected
值嵌入OnNext
条消息中。以下是如何做到这一点:
public ConnectionStatus(CancellationToken token, short timeoutSeconds = 15)
{
pending.Select(_ => connected
.Timeout(TimeSpan.FromSeconds(timeoutSeconds))
.Materialize()
.Select(n => n.Kind == NotificationKind.OnError && n.Exception.GetType() == typeof(TimeoutException)
? Notification.CreateOnNext(false)
: n)
.Dematerialize()
.Take(1)
)
.Switch()
.Subscribe(b => IsConnected = b, token);
}
答案 1 :(得分:3)
以下是在不使用IsConnected
的情况下生成.TimeOut
值流的替代方法:
public class ConnectionStatus
{
private Subject<Unit> pending = new Subject<Unit>();
private Subject<Unit> connected = new Subject<Unit>();
public bool IsConnected { get; private set; }
public ConnectionStatus(CancellationToken token, short timeoutSeconds = 15)
{
pending
.Select(outer =>
Observable.Amb(
connected.Select(_ => true),
Observable.Timer(TimeSpan.FromSeconds(timeoutSeconds)).Select(_ => false)))
.Switch()
.Subscribe(isConnected => IsConnected = isConnected, token);
}
public void ConfirmConnected()
{
connected.OnNext(Unit.Default);
}
public void SetPending()
{
pending.OnNext(Unit.Default);
}
}
Observable.Amb
运算符只是从任何一个observable产生一个值得到一个值 - 它最好用异常编码。