当前位置:必发365电子游戏 > 编程 > 必发365登录WCF学习之旅—HTTP双工方式(七十)
必发365登录WCF学习之旅—HTTP双工方式(七十)
2019-12-19

                WCF学习之旅—须要与回复方式和单向格局(十四)

                WCF学习之旅—HTTP双工方式(四十)

 

五、TCP双工形式

     上风流洒脱篇小说中我们学习了HTTP的双工格局,大家明天就学习一下TCP的双工格局。

必发365登录,      在一个基于面向服务的遍及式情形中,依靠贰个标准的、平台毫无干系的通讯左券,使各样服务通过SOAP Message实现互相之间的相互影响。这几个相互作用的长河实际上正是音信置换的进程。WCF支持分化样式的音讯调换,大家把那称为新闻置换方式(Message Exchange Pattern(简单称谓MEP),下同), 不以为奇的MEP满含: 央浼/答复,单向形式和双工格局。通过选择双工的MEP,我们可以实现在劳务端调用客商端的操作。即便WCF为我们兑现底层的通信细节,使得大家把精力转移到事情逻辑的落到实处,进行与通讯公约非亲非故的编制程序,可是对通讯公约的驾驭有助于我们依照所处的切切实实条件选拔三个伏贴的通讯公约。谈到通讯公约, WCF 平常选择的是以下4个:Http,TCP,Named Pipe,MSMQ。

      大家用上风度翩翩篇章( WCF学习之旅—HTTP双工方式(三十))中的示例,进行一下修正,形成叁个TCP双向通讯的WCF服务应用程序。上面直接上代码。


1.Contract

 

using Contracts;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text; 

namespace Contracts
{

    // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IBookService”。
    [ServiceContract(CallbackContract = typeof(ICallback))]
    public interface IBookService
    {

       /// <summary>
       /// 请求与答复模式,默认模式
       /// </summary>
       /// <param name="Id">书籍ID</param>
       /// <returns></returns>
        [OperationContract]
        string GetBook(string Id);
        /// <summary>

        /// 单工模式,显示名称
        /// </summary>
        /// <param name="name">书籍名称</param>
        [OperationContract(IsOneWay = true)]
        void ShowName(string name);
        /// <summary>
        /// 双工模式,显示名称
        /// </summary>
        /// <param name="name">书籍名称</param>
        [OperationContract(IsOneWay = true)]
        void DisplayName(string name);


    }

}





using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text; 

namespace Contracts
{ 

    public interface ICallback
    {

        [OperationContract(IsOneWay = true)]
        void DisplayResult(string result);

    }
}

 

 

2.WcfServiceLib

using Contracts;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;


namespace WcfServiceLib
{

    // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“BookService”。

    // 注意: 为了启动 WCF 测试客户端以测试此服务,请在解决方案资源管理器中选择 BookService.svc 或 BookService.svc.cs,然后开始调试。
    public class BookService : IBookService
    {

        /// <summary>
        /// 请求与答复模式,默认模式
        /// </summary>
        /// <param name="Id">书籍ID</param>
        /// <returns></returns>
        public string GetBook(string Id)
        {

            System.Threading.Thread.Sleep(20000);
            int bookId = Convert.ToInt32(Id);
            Books book = SetBook(bookId);
            string xml = XMLHelper.ToXML<Books>(book);
            return xml; 

        }



        public Books SetBook(int Id)
        {

            Books book = new Books();
            book.BookID = Id;
            book.AuthorID = 1;
            book.Category = "IBM";
            book.Price = 39.99M;
            book.Numberofcopies = 25;
            book.Name = "DB2数据库性能调整和优";
            book.PublishDate = new DateTime(2015, 2, 23);
            return book;
        }

        /// <summary>
        /// 单工模式,显示名称
        /// </summary>
        /// <param name="name">名称</param>
        public void ShowName(string name)
        {

            string result = string.Format("书籍名称:{0},日期时间{1}", name, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            Console.WriteLine("rn" + result);          

        }

        /// <summary>
        /// 双工模式,回调显示结果
        /// </summary>
        /// <param name="name">名称</param>
        public void DisplayName(string name)
        {
            string result=string.Format("书籍名称:{0},日期时间{1}", name, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            Console.WriteLine("rn" + result);
            ICallback call = OperationContext.Current.GetCallbackChannel<ICallback>();
            call.DisplayResult("回调客户端---"+result);

        }

    }

}

 

      在服务端,通过OperationContext.Current.GetCallbackChannel来获得客商端钦赐的CallbackContext 实例,进而调用客商端的操作。

3.Hosting:

宿主配置文件:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />

  </startup>
  <system.serviceModel>
    <diagnostics>
      <messageLogging logEntireMessage="true" logKnownPii="false" logMalformedMessages="true"
        logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" />
      <endToEndTracing propagateActivity="true" activityTracing="true"
        messageFlowTracing="true" />
    </diagnostics>


    <services>
      <service  name="WcfServiceLib.BookService">
        <endpoint address="net.tcp://127.0.0.1:9999/BookService" binding="netTcpBinding"
        contract="Contracts.IBookService" />

      </service>
    </services>
  </system.serviceModel>
</configuration>

 

 

      大家透过netTcpBinding来模拟基于TCP的双向通讯。代码如下:

using Contracts;
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Text;
using System.Threading.Tasks;
using WcfServiceLib;



namespace ConsoleHosting
{

    class Program
    {

        static void Main(string[] args)
        {
            Console.WriteLine("输入启动方式,C--Code A -- App.config方式!");
            string key = Console.ReadLine();
            switch (key)
            {
                case "C":
                    StartByCode();
                    break;
                case "A":
                    StartByConfig();
                    break;
                default:
                    Console.WriteLine("没有选择启动方式,使用默认方式");
                    StartByCode();
                    break;

            }
        }

        private static void StartByCode()
        {

            //创建宿主的基地址
            Uri baseAddress = new Uri("http://localhost:8080/BookService");
            //创建宿主
            using (ServiceHost host = new ServiceHost(typeof(BookService), baseAddress))
            {

                //向宿主中添加终结点
                host.AddServiceEndpoint(typeof(IBookService), new WSDualHttpBinding(), baseAddress);
                if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)

                {
                    //将HttpGetEnabled属性设置为true
                    ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
                    behavior.HttpGetEnabled = true;
                    behavior.HttpGetUrl = baseAddress;
                    //将行为添加到Behaviors中 

                    host.Description.Behaviors.Add(behavior);
                    //打开宿主

                    host.Opened += delegate
                    {
                        Console.WriteLine("BookService控制台程序寄宿已经启动,HTTP监听已启动....,按任意键终止服务!");
                    };

                    host.Open();
                    //print endpoint information                  

                    Console.ForegroundColor = ConsoleColor.Yellow;
                    foreach (ServiceEndpoint se in host.Description.Endpoints)
                    {
                        Console.WriteLine("[终结点]: {0}rnt[A-地址]: {1} rnt [B-绑定]: {2} rnt [C-协定]: {3}",
                     se.Name, se.Address, se.Binding.Name, se.Contract.Name);
                    }
                    Console.Read();
                }
            }

        }

        private static void StartByConfig()
        {
            using (ServiceHost host = new ServiceHost(typeof(BookService)))
            {
                host.Opened += delegate
                {

                    Console.WriteLine("BookService控制台程序寄宿已经启动,TCP监听已启动....,按任意键终止服务!");
                };

                host.Open();
                //print endpoint information                 

                Console.ForegroundColor = ConsoleColor.Yellow;
                foreach (ServiceEndpoint se in host.Description.Endpoints)
                {
                    Console.WriteLine("[终结点]: {0}rnt[A-地址]: {1} rnt [B-绑定]: {2} rnt [C-协定]: {3}",
                 se.Name, se.Address, se.Binding.Name, se.Contract.Name);

                }

                Console.Read();
            }

        }

    }

}

 

 

4.客户端:

    配置文件中的新闻实行改造:

  <system.serviceModel>
        <client>
           <endpoint address="net.tcp://localhost:9999/BookService" binding="netTcpBinding"

                 bindingConfiguration="" contract="Contracts.IBookService"

                 name="BookServiceEndpoint" />
        </client>
    </system.serviceModel>

 

      接下去贯彻对双工服务的调用,上边是有关的安排和托管程序。在劳务调用程序中,通过 DuplexChannelFactory<TChannel>制造服务代办对 象,DuplexChannelFactory<TChannel>和ChannelFactory<TChannel>的效率都是三个劳务代办对象的创立工厂,可是DuplexChannelFactory<TChannel>特意用来基于双工通讯的服务代办的创立。在成立DuplexChannelFactory<TChannel>在此以前,先创设回调对象,并经过InstanceContext对回 调对象进行包装。代码如下:

private void btnTcpDuplex_Click(object sender, EventArgs e)
        { 

            DuplexChannelFactory<IBookService> channelFactory = new DuplexChannelFactory<IBookService>(instanceContext, "BookServiceEndpoint");
            IBookService client = channelFactory.CreateChannel();



            //在BookCallBack对象的mainThread(委托)对象上搭载两个方法,在线程中调用mainThread对象时相当于调用了这两个方法。 

            textBox1.Text += string.Format("开始调用wcf服务:{0}rnrn", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));

            client.DisplayName("TCP---科学可以这样看丛书");

            textBox1.Text += string.Format("rnrn调用结束:{0}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
        }

 

       在开创 DuplexChannelFactory< IBookService >中,钦赐了Callback Context Instance: 一个兑现了Callback Contract的BookCallBack对象。该对象在Service中通过 OperationContext.Current.GetCallbackChannel<ICallback>(卡塔尔(قطر‎得到。

透过运路程序之后的结果如下图:

 必发365登录 1

 

  2.必发365登录WCF学习之旅—HTTP双工方式(七十)。 依据Http的双向通信V.S.基于TCP的双向通信

       由于Http和TCP在分级契约上的差距,他们达成双向通讯的发式是莫衷一是的。

       Http是多个应用层的磋商,它的机要特色正是无连接和无状态。它利用守旧的“央浼/回复”的办法开展通讯,客户端发送Http Request须求服务端的有个别财富,服务端选拔到该Http Request, 回发对应的Http Response。当顾客端选择到相应的Response,该连接就能够倒闭。也正是说客户端和服务端的 连接仅仅维持在发送Request到接纳到Response那大器晚成段时间内。同期,每一回基于Http的 连接是并行独立,互不相干的,当前连接无法拿到上叁回接二连三的气象。为了保留调用的的景色音讯,ASP.NET通过把意况信息保存在服务端的Session之中,具体的做法是:ASP.NET为各类Session创造贰个Unique ID,与之提到一个HttpSessionState对象,并把状态新闻保存在内部存款和储蓄器中也许长久的存款和储蓄媒质(例如SQL Server)中。而WCF则选取别的的法门达成对Session的帮助:每一种Session关联到有个别ServiceInstance上。

       大家来说一下HTTP双向通讯的长河,当客商端通过HTTP要求调用WCF服务在此之前,会有四个终结点在客户端被成立,用于监听服务端对它的Request。顾客端对 WCF服务的调用会建构四个客商端到服务端的连年,当WCF服务在试行操作进度中须要回调对应的客商端,实际上会确立另二个服务端到客商端的Http 连接。即使大家时候说WCF为支撑双向通信提供叁个双工通道,实际上那些双工通道是由八个HTTP连接组成的。

      再来看一下TCP的双向通信的经过,对于TCP传输层左券,它则是贰个依照连接的商量,在正规打开数据传输的先头,必供给在客户端和服务端之间创设二个连接,连接的确立通过优异的“3次握手”来贯彻。TCP天生就持有双工的风味,也正是说当连接 被创建之后,从客商端到服务端,和从服务端到顾客端的多寡传递都足以接收同二个老是来达成。对于WCF中的双向通讯,客商端调用服务端,服务端回调客商端的操作使用的都是同二个接连、同一个坦途。所以基于TCP的双工通讯格局才是当真含义上的双工通讯模式。