WCF伺服器向客戶端播送訊息和心跳檢測
阿新 • • 發佈:2019-01-01
在利用WCF服務的時候,通常只是在伺服器監聽客戶端呼叫服務。但是WCF服務本就是對TCP, HTTP等各種通訊方式的封裝了所有SOCKET能夠實現的東西,WCF服務應該也能實現。
前面寫過一次部落格,利用WCF服務的會話模式實時檢測客戶端異常掉線。但是對於拔出網線的異常並沒有反應。在這裡我們利用WCF服務的雙工通訊來在伺服器進行心跳檢測,以識別客戶端的掉線.。同時利用雙工通訊向多個已經連線客戶端播送訊息。
所有的操作正如前面一篇部落格一樣都是建立在WCF服務會話模式的基礎上。
1。心跳
前篇已經解釋過為何要用會話模式了,不再多說。直接看步驟
1>. 先在WCF服務 IService 裡面定義回撥介面。回撥函式在客戶端實現 這裡不再列出 如下
[ServiceContract(CallbackContract =(typeof(IDataServiceCallback)))]
public interface IDataServiceCallback
{
[OperationContract(IsOneWay =true)]
void SendBeat();
}
2>. 在Service.svc 中開啟會話模式,並在建構函式中開啟心跳執行緒
[ServiceBehavior(IncludeExceptionDetailInFaults =true,InstanceContextMode =InstanceContextMode.PerSession,ConcurrencyMode =ConcurrencyMode.Multiple)]
線上程中每隔5秒鐘呼叫一次回撥函式,並用try{}catch{}塊包圍OperationContext context; MessageProperties properties; RemoteEndpointMessageProperty endpoint; string loginID = null; IDataServiceCallback callback; private string loginState; Thread th; public DataService() { context = OperationContext.Current; //獲取登入的時間和IP properties = context.IncomingMessageProperties; //獲取訊息傳送的遠端終結點IP和埠 endpoint = properties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty; loginState = "登入成功"; callback = context.GetCallbackChannel<IDataServiceCallback>(); th = new Thread(TestBeat); th.IsBackground = true; th.Start(); }
public void TestBeat()
{
try
{
while (true)
{
Thread.Sleep(5000);
try
{
callback.SendBeat();
}
catch(CommunicationException)
{
userInfoDAL.UpdateState(endpoint.Address, false, loginState);
UserInfoDataSource.UpdateRowOut(endpoint.Address, loginState);
}
}
}
catch (ThreadAbortException) { }
}
如上程式碼所示,如果C-S之間的網線被拔出 就能catch到錯誤此時會話就會終止,你便可以在catch中將你儲存的連線使用者剔除,或者如上篇所屬在Dispose()中剔除, 因為如果信道出錯會話終止,此例項就會呼叫Dispose()函式登出此類. 伺服器心跳先到這兒
2。伺服器向客戶端單播或多播訊息。
同樣是利用雙工通訊。正如Socket一樣 伺服器儲存所有的連線的客戶端Socket WCF服務同樣也需要儲存這樣類似的東西。但是什麼,經過一番研究和推導,它就是服務例項Service 即Service.svc的例項化物件。下面看步驟
1>. 先在WCFService專案中新增一個類,用於儲存連線的服務例項
public class Users
{
public static List<Service1> listChannel = new List<Service1>();
public static void Add(Service1 service1)
{
listChannel.Add(service1);
}
}
2>. 然後再Service.svc的建構函式中儲存所有連線的服務例項
public Service1()
{
callback = OperationContext.Current.GetCallbackChannel<ICalculatorCallback>();
Users.Add(this);
}
3>. 多播資料 這裡我只展示多播函式,單播只要找對應客戶端IP就好。
先定義多播契約函式
[OperationContract]
void BroadCast(string str);
實現多播函式
public void BroadCast(string str)
{
Console.WriteLine("獲得[" + remp.Address + ":" + remp.Port + "]傳送過來的訊息:" + str);
foreach (Service1 context in Users.listChannel)
{
context.callback.SendString(remp.Address, remp.Port, str);
}
}
然後我們就可以在客戶端利用多播函式向其他客戶端傳送訊息了。 下面是我試驗截圖
從左到右依次是三個客戶端,每個客戶端都呼叫一次多播向其他客戶端傳送訊息. 如第一個 先向服務傳送訊息,然後自己接到服務發的訊息,然後是我的一些測試。 在最後收到第二和第三個客戶端發來的訊息。第二個客戶端最後只接受到第三個客戶端發來的訊息。與Socket 程式設計效果完全一樣甚至更方便。