我没有在 WCF 中使用过 NetNamedPipes,但我花在学习 NetTcp 超时值上的时间比我关心的要多。我为我的 NetTcpBindings 使用以下配置,并祝连接保持活跃。
服务器:
<binding name="MyBindingName" sendTimeout="00:00:30" receiveTimeout="infinite">
<reliableSession enabled="true" inactivityTimeout="00:05:00" ordered="true" />
<security mode="None" />
</binding>
客户:
<binding name="MyBindingName" closeTimeout="00:00:30" openTimeout="00:00:30" receiveTimeout="infinite" sendTimeout="00:00:30">
<reliableSession enabled="true" inactivityTimeout="00:01:00" ordered="true" />
<security mode="None" />
</binding>
我花费最多时间的重要设置是 sendTimeout 和 receiveTimeout。如果您的 receiveTimeout 与您的 send 相同或小于您的 send,则一旦达到该超时,通道将丢弃。如果接收更高并且发送高于阈值,则通道将触发传输级别保持活动。根据我的测试,sendTimeout 阈值为 30 秒。任何小于此的内容都不会发送keepalives。
此外,我有一个基于计时器的 keepalive 调用,我每分钟执行一次,以确保通道正常运行。该调用只是对布尔返回成员的调用:
[OperationContract(IsOneWay = false, IsInitiating = false, IsTerminating = false)]
bool KeepAlive();
public bool KeepAlive()
{
return true;
}
您还可以获取频道事件(如果您在正确的时间获得它们)并在发生不良情况时重新打开连接:
InstanceContext site = new InstanceContext(this);
_proxy = new MyServiceChannel(site);
if (_proxy != null)
{
if (_proxy.Login())
{
//Login was successful
//Add channel event handlers so we can determine if something goes wrong
foreach (IChannel a in site.OutgoingChannels)
{
a.Opened += Channel_Opened;
a.Faulted += Channel_Faulted;
a.Closing += Channel_Closing;
a.Closed += Channel_Closed;
}
}
}
我希望其中的一些内容可以转化为 NetNamedPipes 并为您提供价值。
编辑:用于捕获服务器重新启动问题的更多选项
当服务器重新启动时,它应该导致客户端的通道关闭或出现故障。在客户端捕获这些事件将使您可以选择使用重新连接计时器,直到服务再次可用。
private void Channel_Faulted(object sender, EventArgs e)
{
IChannel channel = sender as IChannel;
if (channel != null)
{
channel.Abort();
channel.Close();
}
//Disable the keep alive timer now that the channel is faulted
_keepAliveTimer.Stop();
//The proxy channel should no longer be used
AbortProxy();
//Enable the try again timer and attempt to reconnect
_reconnectTimer.Start();
}
private void _reconnectTimer_Tick(object sender, System.EventArgs e)
{
if (_proxy == null)
{
InstanceContext site = new InstanceContext(this);
_proxy = new StateManagerClient(site);
}
if (_proxy != null)
{
if (_proxy.Login())
{
//The connection is back up
_reconnectTimer.Stop();
_keepAliveTimer.Start();
}
else
{
//The channel has likely faulted and the proxy should be destroyed
AbortProxy();
}
}
}
public void AbortProxy()
{
if (_proxy != null)
{
_proxy.Abort();
_proxy.Close();
_proxy = null;
}
}
您需要确保重新连接计时器的登录尝试是在后台线程上异步完成的,这样它们就不会在每次尝试登录时都挂起 UI。YMMV