[英]How can I make Named Pipe binding reconnect automatically in WCF
我正在編寫一個只接收來自本地主機的電話的服務。 性能很重要,所以我想我會嘗試NetNamedPipeBinding而不是NetTcpBinding ,看看我是否能看到任何明顯的性能提升。
如果客戶端在對服務器執行了一個或多個請求之后,在較長時間內處於空閑狀態,則下一個請求似乎會因綁定中的某些空閑超時而失敗。 服務重新啟動時也會發生同樣的事情。
我需要我的客戶端能夠在允許的情況下保持連接打開,以避免與設置新連接相關的開銷。 我還需要能夠不時重新啟動服務,並讓客戶端在發現連接已終止時自動重試。
我知道這可以通過NetTcpBinding中的可靠性內容來支持,但是如何在NetNamedPipeBinding中獲得相同級別的重新連接可靠性呢? 它甚至可能嗎?
這個問題在某種程度上是學術性的,因為它不是使用NetNamedPipes的要求,我可以很容易地采用它來使用tcp綁定,但它是一個癢,我真的想抓它。
我的經驗是,當使用NetNamedPipes時,綁定上的“ReceiveTimout”功能就像“不活動超時”而不是接收時間。 請注意,這與NetTCPBinding的工作方式不同。 使用TCP,它實際上是一個接收超時,並且您可以通過可靠的消息傳遞配置單獨的非活動超時。 (它似乎也與SDK文檔相反,但很好)。
要解決此問題,請在創建綁定時將RecieveTimout設置為較大的值。
例如,如果您在程序上創建綁定...
NetNamedPipeBinding myBinding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
myBinding.ReceiveTimeout = TimeSpan.MaxValue;
或者,如果您關心以聲明方式創建綁定...
<netNamedPipeBinding>
<binding name="myBinding" receiveTimeout="infinite">
</binding>
</netNamedPipeBinding>
我沒有在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與您的發送相同或更少,則一旦達到超時,通道將會丟棄。 如果接收較高且發送高於閾值,則通道將觸發傳輸級別keepalive。 從我的測試中,sendTimeout閾值是30秒。 任何低於此值的東西都不會被發送。
此外,我有一個基於計時器的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。 因人而異
我一直在研究連接兩天的TCP連接丟失的問題,並得出結論,很多人在WCF中建立連接時錯過了一個重要的觀點。 每個人似乎都在做的是創建一個通道,然后嘗試在應用程序的生命周期中保持它,播放各種骯臟的技巧以保持TCP會話存活。 這不是它的意思。
您應該創建一個頻道,在您的服務上執行一個(或在第一個之后不久)調用,然后關閉並處置該頻道。 這將給你(幾乎)無狀態操作,你不必為保持會話活着而煩惱,這是你不應該首先想要的。
您會發現創建和關閉通道(來自重用的ChannelFactory)的開銷可以忽略不計,在典型的機器上只需要幾十納秒。
每個人都在啟動的receiveTimeout屬性定義了一個頻道在被自動刪除之前可以保持空閑的時間,這告訴你頻道不應該長時間保持打開(默認為1分鍾)。 如果將receiveTimeout設置為TimeSpan.MaxValue,它將使您的頻道保持更長時間,但這不是它的用途,也不是您在實際場景中想要的。
最終讓我走上正軌的是http://msdn.microsoft.com/en-us/library/ms734681.aspx ,它提供了一個可怕的錯誤示例,但確實展示了如何使用ChannelFactory。 響應者指出錯誤並設置記錄,所以總而言之,你可以在這里得到你需要的一切。
然后,我所有的問題都結束了。 不再“嘗試對不是套接字的東西進行操作”而不再“遠程主機強行關閉現有連接”。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.