程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 用WCF做聊天程序

用WCF做聊天程序

編輯:關於.NET

先看一個截圖。

上面的圖,各位乍一看,可能會覺得是用Socket編寫的聊天程序。告訴你吧,這玩意兒不是用Socket實現,呵呵,當然它的底層肯定與Socket有一定關系,我只說我的代碼沒有用到socket而已。

那麼,除了Socket可以用於通信,還有其他技術嗎?有啊,首先,如果你足夠強大,用HTTP也行,但HTTP初始化的過程貌似比較慢。那麼還有嗎?當然了,各位還記得.NET以前有一個很X但又很少被關注的技術——Remoting。用過吧?沒用過也沒關系,因為它已經有替代品了。

這時候大家肯定想到WCF不是一盞“省油”的燈,其實不然,對比於用Socket要編寫的代碼數量和維護成本,用WCF編寫網絡通信程序,不僅省油,而且省時省力,最重要的是省心。所以,人的健康,心理健康是占主導的,你看一個心理不健康的人,其身體也不會健康到哪裡去,今天這病明天那病。

因而,編程這事啊,越省心越好,有利於我們的健康,賺錢永遠不是目的,身心健康才是活在這個世界上的主旋律,至於你信不信,反正我深信不疑。

我就這個WCF版的聊天程序的大致思路說一說。

這個程序既可以充當服務器端也同時作為客戶端,每個應用實例都扮演著雙重角色。這裡我不需要引用服務。首先看服務協定和服務類。

using System;     
using System.ServiceModel;     
         
namespace ServiceDef     
{     
    [ServiceContract]     
    public interface IService     
    {     
        [OperationContract(IsOneWay = true)]     
        void SendMessage(string msg);     
    }     
         
    /// <summary>     
    /// 服務     
    /// </summary>     
    public class MyChatService : IService     
    {     
        /// <summary>     
        /// 收到消息後引發的事件     
        /// </summary>     
        public event EventHandler<MessageReceiveEventArgs> MessageGot;     
        public MyChatService()     
        {     
            MessageGot += new EventHandler<MessageReceiveEventArgs>(TestApp.Form1.GetMessageCallBack);     
        }     
        public void SendMessage(string msg)     
        {     
            if (MessageGot != null)     
            {     
                MessageGot(this, new MessageReceiveEventArgs(msg));     
            }     
        }     
    }     
         
    /// <summary>     
    /// 收到消息後引發事件的參數     
    /// </summary>     
    public class MessageReceiveEventArgs : EventArgs     
    {     
        private string m_Message = string.Empty;     
        public MessageReceiveEventArgs(string message)     
        {     
            this.m_Message = message;     
        }     
         
        public string MessageText     
        {     
            get { return this.m_Message; }     
        }     
    }     
         
}

服務協定沒什麼好看的了,相信大家都會寫,這裡的服務類與以往的有些不同,大家看到,裡面定義了一個事件。那麼,為什麼要這樣做呢?為什麼要在服務方法被調用時引發這個事件呢?

想一想,我們以上代碼是與UI分離的,也就是說,與UI分離是一種很好的編程方法,這樣在修改維護時不會搞得亂七八糟。但是,我們都知道世間萬物皆為陰陽所生,所以才有太極生兩儀,兩儀生四象,四象成八卦。而陰與陽是統一的,陰中有陽,陽在有陰。

我們的應用程序的UI就是陽,而業務邏輯就是陰,所以編程就是這麼簡單——陰陽互動。為了完成陰中有陽的功能,我們要想辦法讓這些代碼與窗口上的控件互動,當然方法很多,也相當靈活。使用事件是比較好的。

於是,在服務類中定義一個事件,而事件的處理方法在主窗口類中定義,這樣一來,陽與陰之間就有了一個可以相通的渠道。

為了使用訪問方便,在窗口類中定義的處理事件的方法使用靜態方法,靜態方法的好處在於,它不基於對象,而是基於類的,你去到哪裡都可以訪問,它是全球化的。

這時候有人會問了,靜態方法不能訪問類對象的成員,那麼這個靜態方法又如何與窗體上的控件互動呢?技巧都是拿來用的。有了靜態方法,難道我不能在窗口類中定義一個保存當前類實例的靜態變量嗎?

比如,我這個窗口的類名為FormMain,我只要在FormMain裡面定義一個static FormMain CurrentForm = null;就完事了,這樣不就可以在靜態方法中訪問了嗎?

只要在FormMain的構造函數中賦值就行了,CurrentForm = this;

比如本例的代碼:

        #region 靜態成員     
        static Form1 CurrentInstance = null;     
        public static void GetMessageCallBack(object sender, ServiceDef.MessageReceiveEventArgs e)     
        {     
            if (CurrentInstance != null)     
            {     
                CurrentInstance.AddMessageToListBox(e.MessageText);     
            }     
        }     
        #endregion     
         
        public Form1()     
        {     
         
            InitializeComponent();     
            CurrentInstance = this;     
…………

你看,這就成了。

然後當然是定義服務器了,這裡我們只有一個終結點,就是上面的IService,所以不用基址了,因為我們也不需要引用服務,直接利用ChannelFactory就行了。

#region 與服操作有關     
ServiceHost host = null;     
         
/// <summary>     
/// 啟動服務     
/// </summary>     
/// <param name="port">監聽端口</param>     
void OpenService(int port)     
{     
    host = new ServiceHost(typeof(ServiceDef.MyChatService));     
    NetTcpBinding binding = new NetTcpBinding();     
    binding.Security.Mode = SecurityMode.None;     
    host.AddServiceEndpoint(typeof(ServiceDef.IService), binding, "net.tcp://" + Dns.GetHostName() + ":"+ port.ToString() + "/chatsvc/");     
    host.Opened += host_Opened;     
    host.Closed += host_Closed;     
    try 
    {     
        host.Open();     
    }     
    catch (Exception ex)     
    {     
        ShowMessage(ex.Message);     
    }     
}     
         
void host_Closed(object sender, EventArgs e)     
{     
    ShowMessage("服務已關閉。");     
}     
         
void host_Opened(object sender, EventArgs e)     
{     
    ShowMessage("服務已啟動。");     
}     
         
/// <summary>     
/// 關閉服務     
/// </summary>     
void CloseService()     
{     
    if (host != null)     
    {     
        host.Close();     
        host.Opened -= host_Opened;     
        host.Closed -= host_Closed;     
    }     
}     
        
#endregion

好了,接下來就是發送消息,其實就是調用服務方法IService.SendMessage,這裡我們只用ChannelFactory<TChannel>工廠來生產一個IService通道,而後直接調用就可以了,就不必引用服務,也不用生成什麼WSDL文件,也不考慮SOAP版本了。

// 發送消息,即調用服務     
NetTcpBinding binding =new NetTcpBinding();     
binding.Security.Mode = SecurityMode.None;     
         
try 
{     
    ServiceDef.IService ep = ChannelFactory<ServiceDef.IService>.CreateChannel(binding,new EndpointAddress("net.tcp://" + txtSvrHostName.Text + ":" + rmPort.ToString() + "/chatsvc/"));     
    ep.SendMessage(txtSendMessage.Text);     
    txtSendMessage.Clear();     
}     
catch (Exception ex)     
{     
    ShowMessage(ex.Message);     
}

哈哈,是不是很簡單,而且,你也可以想到,如果用WCF來做文件傳輸,比如PC與手機上的文件傳送,是不是很方便呢?也不必擔心TCP粘包問題。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved