1. 程式人生 > >Winfrom 使用WCF 實現雙工通訊

Winfrom 使用WCF 實現雙工通訊

實現雙工通訊主要分三步。

  1. 通訊介面的定義;
  2. 被呼叫介面的實現
  3. 雙工通道的建立

請先引用DLL(CSDN的程式碼編輯器真尼瑪蛋疼)


整個解決方案的結構


1、通訊介面的定義;

服務端呼叫客戶端介面IServerCallClient

    /// <summary>
    /// 伺服器呼叫客戶端介面
    /// </summary>
    public interface IServerCallClient
    {
        /// <summary>
        /// 伺服器讀取客戶端的IP
        /// </summary>
        /// <returns></returns>
        [OperationContract]
        IPEndPoint ServerRequestCLientIP();
        /// <summary>
        /// 伺服器傳送訊息給客戶端
        /// </summary>
        /// <param name="text"></param>
        [OperationContract]
        void ServerSayMSG(string text);
    }

客戶端呼叫服務端介面IClientCallServer

<span style="font-weight: normal;">    [ServiceContract(CallbackContract =typeof(IServerCallClient))]//指定回撥的介面
    public interface IClientCallServer
    {
        /// <summary>
        /// 客戶端傳送訊息給伺服器
        /// </summary>
        /// <param name="text"></param>
        [OperationContract]//指定操作約束,不新增該介面方法不可使用
        void ClientSayToServer(string text);
        /// <summary>
        /// 客戶端讀取服務端時間
        /// </summary>
        /// <returns></returns>
        [OperationContract]
        DateTime ClientRequestTime();
    }</span>

上面的兩個介面是單獨的一個專案。

雙方談好了就好互相實現對方的方法。

2、被呼叫介面的實現

客戶端實現服務端介面的類:

    class ServerCallClient :IServerCallClient
    {
        public IPEndPoint ServerRequestCLientIP()
        {
            var ip =new IPEndPoint(IPAddress.Any,10086);
            return ip;
        }
        public void ServerSayMSG(string text)
        {
            File.AppendAllText("收到的資料", text);
        }
    }

服務端實現客戶端介面的類

    /// <summary>
    /// 客戶回撥伺服器類
    /// </summary>
    [ServiceBehavior(InstanceContextMode =InstanceContextMode.Single)]//通道只建立一個除非斷開才新建(SessionID是同一個)
    public class ClientCallServer : IClientCallServer, IDisposable
    {
        public static List<IServerCallClient> ServerCallClientList { get; set; }=new List<IServerCallClient>();
        /// <summary>
        /// 返回伺服器時間
        /// </summary>
        /// <returns></returns>
        public DateTime ClientRequestTime()
        {
            return DateTime.Now;
        }
        /// <summary>
        /// 客戶端列表
        /// </summary>
        /// <summary>
        /// 服務端向客戶端發資料
        /// </summary>
        /// <param name="text"></param>
        public void ClientSayToServer(string text)
        {
            var info = OperationContext.Current;
            File.AppendAllText("receive.txt",info.SessionId+text);//收到的資料存在檔案
        }
        public void Dispose()
        {
            ServerCallClientList.Clear();
        }
        #endregion
    }

3、雙工通道的建立

服務端通道的建立
            ServiceHost serviceHost = new ServiceHost(typeof(ClientCallServer));//<span style="font-family: Arial, Helvetica, sans-serif;">指定回撥的類</span>
            serviceHost.AddServiceEndpoint(typeof(IClientCallServer),new WSDualHttpBinding(), "http://localhost:12345");//指定客戶端的介面,通訊格式,伺服器的地址
            serviceHost.BeginOpen(callback=>
            {
                serviceHost.EndOpen(callback);
                textBox1.Invoke(new Action(delegate {//不解釋也能看得懂吧
                    textBox1.AppendText("服務開啟" + Environment.NewLine);
                }));
            },null);

客戶端通道的建立
var rand = new Random(); 
 InstanceContext context = new InstanceContext(new ServerCallClient());//指定回撥的類 
 WSDualHttpBinding binding = new WSDualHttpBinding() { ClientBaseAddress = new Uri($"http://localhost:{rand.Next(10000, 20000)}") };//指定客戶端地址; 
 using (DuplexChannelFactory proxy = new DuplexChannelFactory(context, binding))//建立通道管理器
 {
  IClientCallServer client = proxy.CreateChannel(new EndpointAddress("http://localhost:12345"));// 建立用於將訊息傳送到特定終結點地址的服務的通道client.ClientRequestTime(); 
  client.ClientSayToServer("尼瑪"); 
 }