WCF筆記(9)羣聊程序

今天,我們來做一個可以羣聊的應用,就像QQ羣那樣,一個服務器端,N個客戶端,服務器端運行後,每個客戶端啓動的時候會自動連接服務器生成會話,只要其中任一個客戶端向服務器發送消息,服務器都會將消息羣發到所有客戶端。

用到的知識點:

  1. 在進程中承載WCF服務。
  2. 會話的使用。
  3. 回調。
1、還是先從服務端開始

    /// <summary>
    /// 1、定義回調接口
    /// </summary>
    public interface ICallback
    {
        [OperationContract(IsOneWay=true)]
        void SendToClients(string nickname, string message, DateTime time);
    }

    /// <summary>
    /// 2、定義服務協定
    /// </summary>
    [ServiceContract(CallbackContract=typeof(ICallback),SessionMode= SessionMode.Required )]
    public interface IService
    {
        [OperationContract(IsOneWay=true, IsInitiating=true,IsTerminating=false)]
        void Begin();
        [OperationContract(IsOneWay=true)]
        void SendMessage(string nickname, string message, DateTime time);
        [OperationContract(IsOneWay=true,IsInitiating=false,IsTerminating=true)]
        void End();
        /*Begin方法和End方法分別是啓動會話和終止會話,這樣每接入一個客戶端連接就會實例化一個服務類;
         * 這樣就可以確保每個客戶端都與服務器維持一個會話。
        */
    }

    /// <summary>
    /// 3、實現服務協定
    /// </summary>
    [ServiceBehavior(IncludeExceptionDetailInFaults=true,InstanceContextMode= InstanceContextMode.PerSession)]
    public class MyService : IService
    {
        //聲明一個靜態的字典,存儲所有客戶端的會話ID所對應的回調
        public static Dictionary<string, ICallback> m_clientCallbacks = new Dictionary<string, ICallback>(); 
       
        /// <summary>
        /// 開始會話,
        /// 獲取所有客戶端的會話ID和回調,並將其存入字典
        /// </summary>
        public void Begin()
        {
            string sessionId = OperationContext.Current.SessionId;
            ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
            if (sessionId != null) m_clientCallbacks[sessionId] = callback;
        }

        /// <summary>
        /// 從字典中取出所有回調,
        /// 並把接收的參數傳給回調方法;
        /// 在回調調用後,這些消息就會轉發到所有連接的客戶端,從而實現羣聊。
        /// </summary>
        /// <param name="nickname">用戶暱稱</param>
        /// <param name="message">發送的信息</param>
        /// <param name="time">時間</param>
        public void SendMessage(string nickname, string message, DateTime time)
        {
            foreach (ICallback cb in m_clientCallbacks.Values)
            {
                if (cb != null)
                {
                    cb.SendToClients(nickname, message, time);
                }
            }
        }

        /// <summary>
        /// 結束會話,
        /// 將對應的會話ID和回調從字典中移除
        /// </summary>
        public void End()
        {
            string sessionId = OperationContext.Current.SessionId;
            if (m_clientCallbacks.ContainsKey(sessionId))
            {
                m_clientCallbacks.Remove(sessionId);
            }
        }
    }
這裏在類中,聲明瞭一個靜態的Dictionary<string, ICallBack>,這是一個字典,我想大家猜到了,靜態變量是基於類的,與實例無關,我們可以把它當作全局數據,在字典集合中保存所有接入客戶端的回調,由於每個會話的ID是唯一的,因此,用SessionID作爲Key是比較好操作的。

 //4、配置服務器
        static void Main()
        {
            //服務基地址
            Uri baseUri = new Uri("http://localhost:3000/Service");
            //聲明服務器主機
            using (ServiceHost host = new ServiceHost(typeof(MyService), baseUri))
            {
                //添加綁定和終結點
                NetTcpBinding binding = new NetTcpBinding();
                host.AddServiceEndpoint(typeof(IService), binding, "net.tcp://localhost:2000/test");
                //元數據
                ServiceMetadataBehavior mb = new ServiceMetadataBehavior();
                mb.HttpGetEnabled = true;
                mb.HttpGetUrl = new Uri("http://localhost:1234/WSDL");
                host.Description.Behaviors.Add(mb);
                //啓動服務
                try
                {
                    host.Open();
                    Console.WriteLine("服務已啓動");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                Console.ReadKey();
                //關閉服務
                host.Close();
            }
        }

2、實現客戶端

這裏我做了兩個客戶端,一個是winform的,一個是wpf的。我只粘貼主要代碼,其餘我會上傳到我的資源,大家可以去那裏下載

    /// <summary>
    /// 實現回調接口
    /// </summary>
    public class MyCallback : IServiceCallback
    {
        //事件
        public event EventHandler<CallbcakEventArgs> MessageReceiveEvent;

        //回調中的方法是服務器調用的,
        //在客戶端要想及時偵聽到該方法被調用,可以使用事件;
        //當回調方法被調用,就會觸發事件.
        public void SendToClients(string nickname, string message, DateTime time)
        {
            if (MessageReceiveEvent != null)
            {
                CallbcakEventArgs args = new CallbcakEventArgs(nickname, message, time);
                MessageReceiveEvent(this,args);
            }
        }
    }

    /// <summary>
    /// 事件參數類
    /// </summary>
    public class CallbcakEventArgs:EventArgs 
    {
        private readonly string m_nickname;
        private readonly string m_message;
        private readonly DateTime m_time;
        public CallbcakEventArgs(string nickname,string message,DateTime time)
        {
            m_nickname = nickname;
            m_message = message;
            m_time = time;
        }
        public string NickName 
        {
            get { return m_nickname; }
        }
        public string Message
        {
            get { return m_message; }
        }
        public DateTime Time
        {
            get { return m_time; }
        }
    }

截圖如下:



最後放上最近wcf學習的所有源碼:wcf學習筆記源碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章