(郁闷,不知道字数上限,发现上传不了了,才被迫一分为二,;P)

<system.serviceModel><services><service behaviorConfiguration="WcfDuplexServiceInIIS.StockServiceBehavior"name="WcfDuplexServiceInIIS.StockService"><!--将绑定更改为双向--><endpoint address="ws" binding="wsDualHttpBinding" contract="WcfDuplexServiceInIIS.IStockService"><identity><dns value="localhost" /></identity></endpoint><endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /></service></services><behaviors><serviceBehaviors><behavior name="WcfDuplexServiceInIIS.StockServiceBehavior"><serviceMetadata httpGetEnabled="true" /><serviceDebug includeExceptionDetailInFaults="false" /></behavior></serviceBehaviors></behaviors></system.serviceModel>

上面程序中有一个问题,就是为每个客户端创建线程。这种情况下,客户端个数不可预期(可能是数百万),但是股票个数却有限制(数千)。因此,为每只股票创建线程比为每个客户端创建线程会更好。

下面代码显示了更改。这个例子中,使用HashTable为每一个客户端的更新请求维护股票信息。Update类存储在HashTable中,而每个Update类都运行在自己的线程上。客户回调列表存储在Update类的本地线程中,所以Update类可以关注所有客户端所关联的股票。注意,lock关键字,当访问客户端列表集合时,无论是通过StockService类还是Update类本身都出现了,这样是必要的。一面客户端列表集合不会在StockService类修改之后,在此被Update类重复修改。

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.ComponentModel;
using System.Threading;
using System.Collections.Generic;namespace WcfDuplexServiceInIIS
{public class Update{#region per Stockpublic string ticker;public List<IClientCallback> callbacks = new List<IClientCallback>();#endregionpublic void SendUpdateToClient(){#region per StockRandom w = new Random();Random p = new Random();while (true){Thread.Sleep(w.Next(5000)); //假设更新在此发生
                lock (callbacks)foreach (IClientCallback c in callbacks)try{c.PriceUpdate(ticker, 100.00 + p.NextDouble() * 10);}catch (Exception ex){Console.WriteLine("Error sending cache to client: {0}", ex.Message);}}#endregion}}
}

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Runtime.Serialization;
   5:  using System.ServiceModel;
   6:  using System.Text;
   7:  using System.Threading;
   8:  using System.Collections;
   9:   
  10:  namespace WcfDuplexServiceInIIS
  11:  {
  12:      /// <summary>
  13:      /// 实现双向服务契约的服务端类使用PerSession的InstanceContextMode存储结果。
  14:      /// 一个服务的实例将被绑定到每个双向会话上。
  15:      /// </summary>
  16:      public class StockService : IStockService
  17:      {
  18:          #region per Stock
  19:          #region IStockService Members
  20:   
  21:          public class Worker
  22:          {
  23:              public string ticker;
  24:              public Update workerProcess;
  25:          }
  26:   
  27:          public static Hashtable workers = new Hashtable();
  28:   
  29:          void IStockService.RegisterForUpdates(string ticker)
  30:          {
  31:              Worker w = null;
  32:   
  33:              //如果需要,创建一个新的Worker,并将它添加到hashtable中,而且在新线程中启动它。
  34:              if (!workers.ContainsKey(ticker))
  35:              {
  36:                  w = new Worker();
  37:                  w.ticker = ticker;
  38:                  w.workerProcess = new Update();
  39:                  w.workerProcess.ticker = ticker;
  40:                  workers[ticker] = w;
  41:   
  42:                  Thread t = new Thread(new ThreadStart(w.workerProcess.SendUpdateToClient));
  43:                  t.IsBackground = true;
  44:                  t.Start();
  45:              }
  46:   
  47:              //获取当前指定股票的worker,然后添加客户端代理到它的回调列表中。
  48:              w = (Worker)workers[ticker];
  49:              IClientCallback c = OperationContext.Current.GetCallbackChannel<IClientCallback>();
  50:              lock (w.workerProcess.callbacks)
  51:                  w.workerProcess.callbacks.Add(c);
  52:          }
  53:   
  54:          #endregion
  55:          #endregion
  56:      }
  57:  }

无论是使用线程/客户端实现还是使用线程/股票实现,都存在着可靠性的问题。例如,如果服务无法调用客户端回发操作,它记录一个消息到输出设备上,但是它从未重试。服务端应该重试吗?如果重试频率是多大?到什么时候为止呢?或者,如果有一个预定的窗口,通过它客户端可以在知道服务端将无法接收更新时,更新请求可以被排队,使他们可以推迟时间?这些都是非常重要的问题。这些问题都可以通过使用如BizTalk或类似的消息处理产品解决。消息处理通常其系统的核心功能具有持久存储(数据库、文件系统或消息队列)功能,而且包含强大的配置工具来制定传输和重试策略。但是他们仍然承担性能、复杂度和成本上的考虑。所以这种解决方案非常依赖需求方的意见。

实现双向契约的客户部分

为了加入双向消息交换模式,客户端必须实现WCF的ABCs,即它必须在客户端定义一个服务端发送消息的地址,一个指示服务端如何发送消息到客户端的绑定以及一个明确定义消息格式的契约。幸运的是,当你生成客户端代理和底层管道结构运行时时需要关心的问题。

为了生成客户端代理,可以使用svcutil.exe或者添加服务引用。代理定义一个使用与服务端相同名称的借口,使用Callback在结尾追加。如果服务契约接口是IStockService,客户端借口就是IStockServiceCallback。客户端必须实现一个继承接口的类。

在运行时,就想服务端,客户端通过严格的端点定义然后接收消息。服务端点和客户端点主要的不同是客户端点是WCF动态创建的。在客户端代码中没有配置文件或明确的ServiceHost调用。再次,WCF照顾到这一点,素以客户端只需要实现一个继承自生成的接口的类。

下面的代码显示了客户端调用StockServcie服务的RegisterForUpdates方法来请求定期的更新。它同样实现了回调接口,PriceUpdate,正如服务端所要求的那样,实现股票价格的更新。注意,一个InstanceContext对象被实例化,并用来创建代理。InstanceContext对象为服务存储内容信息,如提及的在客户端代表创建的传入和传出管道。

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using System.ServiceModel;
   6:  using DuplexClient;
   7:  using DuplexClient.DuplexStockServiceReference;
   8:   
   9:  namespace DuplexClient
  10:  {
  11:      /// <summary>
  12:      /// 1. 创建一个服务,它包含两个接口。一个是服务接口,另一个是回调接口。
  13:      /// 2. 部署服务。
  14:      /// 3. 使用svcutil.exe生成契约(接口)。
  15:      /// 
  16:      /// 5. 创建一个InstanceContext类的实例。构造函数要求一个客户端类的实例。
  17:      /// 6. 使用构造函数创建一个WCF客户端实例,构造函数需要InstanceContext对象。
  18:      ///     构造函数的第二个参数是配置文件中端点的名字。
  19:      /// 7. 调用方法请求。
  20:      /// </summary>
  21:      class Program
  22:      {
  23:          static void Main(string[] args)
  24:          {
  25:              InstanceContext site = new InstanceContext(new CallbackHandler());
  26:   
  27:              StockServiceClient proxy = new StockServiceClient(site, "WSDualHttpBinding_IStockService");
  28:              try
  29:              {
  30:                  proxy.RegisterForUpdates("中软国际");
  31:                  proxy.RegisterForUpdates("中软股份");
  32:                  proxy.RegisterForUpdates("中软香港");
  33:              }
  34:              catch (TimeoutException timeProblem)
  35:              {
  36:                  Console.WriteLine("The service operation timed out. " + timeProblem.Message);
  37:                  proxy.Abort();
  38:                  Console.Read();
  39:              }
  40:              catch (CommunicationException commProblem)
  41:              {
  42:                  Console.WriteLine("There was a communication problem. " + commProblem.Message);
  43:                  proxy.Abort();
  44:                  Console.Read();
  45:              }
  46:   
  47:              Console.WriteLine("Press Enter or any key to exit");
  48:              Console.ReadLine();
  49:          }
  50:      }
  51:  }

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using DuplexClient;
   6:  using DuplexClient.DuplexStockServiceReference;
   7:   
   8:  namespace DuplexClient
   9:  {
  10:      /// <summary>
  11:      /// 4. 在客户端类中实现回调接口。
  12:      /// </summary>
  13:      public class CallbackHandler : IStockServiceCallback
  14:      {
  15:   
  16:          #region IStockServiceCallback Members
  17:   
  18:          void IStockServiceCallback.PriceUpdate(string ticker, double price)
  19:          {
  20:              Console.WriteLine("Received alert at : {0}. {1}:{2}",System.DateTime.Now,ticker,price);
  21:          }
  22:   
  23:          #endregion
  24:      }
  25:  }

一个服务中的多契约与多端点

服务被定义为端点的集合。每个端点都有地址、绑定和契约。契约是指抛出的端点的什么功能,地址是指应用程序(服务)在网络上所处的位置,而绑定是指如何访问他们。

端点与契约之间有一对多的关系。一个端点只能由一个契约,但是一个契约可以被多个端点引用。虽然端点只能定义一个契约,接口的聚合可以使一个合同抛出多个接口。此外,多个使用相同的绑定的端点,但是契约不同,也可以使用相同的地址。可以想象一个单独的端点可以实现两个契约。

在一个服务中通过多个端点暴露一个契约,你可以通过多种绑定方式实现。你可以使用WS-I基本概念绑定定义一个端点来暴露一个契约,同时可以通过另一个使用TCP协议和二进制编码的端点来暴露它以获得更高性能。通过整合多个接口为一个接口,你可以通过一个服务提供功能的综合访问。

下面代码实现两个服务契约,IGoodStockService和IGreatStockService,共同聚集为第三个服务契约,IStockService。这些接口中的方法定义也聚集在一起。虽然服务接口可以继承,但是[ServiceContract]属性必须定义在每个接口上。

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Runtime.Serialization;
   5:  using System.ServiceModel;
   6:  using System.Text;
   7:   
   8:  namespace WcfMultiServiceInIIS
   9:  {
  10:      [ServiceContract]
  11:      public interface IGoodStockService
  12:      {
  13:          double GetStockPrice(string ticker);
  14:      }
  15:  }

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Runtime.Serialization;
   5:  using System.ServiceModel;
   6:  using System.Text;
   7:   
   8:  namespace WcfMultiServiceInIIS
   9:  {
  10:      [ServiceContract]
  11:      public interface IGreatStockService
  12:      {
  13:          double GetStockPriceFast(string ticker);
  14:      }
  15:  }

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Runtime.Serialization;
   5:  using System.ServiceModel;
   6:  using System.Text;
   7:   
   8:  namespace WcfMultiServiceInIIS
   9:  {
  10:      [ServiceContract]
  11:      public interface IAllStockService : IGoodStockService,IGreatStockService
  12:      {
  13:      }
  14:  }

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Runtime.Serialization;
   5:  using System.ServiceModel;
   6:  using System.Text;
   7:  using System.Threading;
   8:   
   9:  namespace WcfMultiServiceInIIS
  10:  {
  11:      public class AllStockService : IAllStockService
  12:      {
  13:          #region IGoodStockService Members
  14:   
  15:          double IGoodStockService.GetStockPrice(string ticker)
  16:          {
  17:              Thread.Sleep(5000);
  18:              return 94.85;
  19:          }
  20:   
  21:          #endregion
  22:   
  23:          #region IGreatStockService Members
  24:   
  25:          double IGreatStockService.GetStockPriceFast(string ticker)
  26:          {
  27:              return 94.85;
  28:          }
  29:   
  30:          #endregion
  31:      }
  32:  }

下面代码显示了一个配置文件中为三个契约暴露多个端点。一个为IGoodStockService契约,两个端点为IGreatStockService契约,另一个端点为IAllStockService契约。

由于多个端点使用绑定的共享地址,所以必须为每个端点定义不同的地址。相对地址的使用,使每个端点的完整地址就是服务端地址加上相对地址。

<system.serviceModel><services><service behaviorConfiguration="WcfMultiServiceInIIS.AllStockServiceBehavior"name="WcfMultiServiceInIIS.AllStockService"><host><baseAddresses><add baseAddress="http://chinasofti-eric/WCFMultiServiceInIIS/"/></baseAddresses></host><endpoint name="GoodStockService" binding="wsHttpBinding" contract="WcfMultiServiceInIIS.IGoodStockServcie"/><endpoint name="BetterStockService" address="better" binding="basicHttpBinding" contract="WcfMultiServiceInIIS.IGreatStockService"/><endpoint name="BestStockService" address="best" binding="wsHttpBinding" contract="WcfMultiServiceInIIS.IGreatStockService"/><endpoint name="AllStockService" address="all" binding="wsHttpBinding" contract="WcfMultiServiceInIIS.IAllStockService"/><endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /></service></services><behaviors><serviceBehaviors><behavior name="WcfMultiServiceInIIS.AllStockServiceBehavior"><serviceMetadata httpGetEnabled="true" /><serviceDebug includeExceptionDetailInFaults="false" /></behavior></serviceBehaviors></behaviors></system.serviceModel>

由于IGreatStockService契约在多个端点中暴露,客户端应用程序在创建代理类实例时必须通过名字引用端点。如果端点名没有定义,WCF会抛出一个错误,因为它无法知道那个端点正要被使用。下面代码显示了如何使用GreatStockServiceClient代理类两次:第一次访问BetterStockService使用basicHttpBinding,第二次访问BestStockService使用wsHttpBinding。

   1:  #region 访问多契约服务
   2:          static void Main(string[] args)
   3:          {
   4:              using (MultiServiceReference.GreatStockServiceClient proxy = 
   5:  new Client.MultiServiceReference.GreatStockServiceClient("BetterStockService"))
   6:              {
   7:                  Console.WriteLine(proxy.GetStockPriceFast("中软国际"));
   8:              }
   9:   
  10:              using (MultiServiceReference.GreatStockServiceClient proxy = 
  11:  new Client.MultiServiceReference.GreatStockServiceClient("BestStockService"))
  12:              {
  13:                  Console.WriteLine(proxy.GetStockPriceFast("中软国际"));
  14:              }
  15:   
  16:              Console.WriteLine("Operation is complete.");
  17:              Console.WriteLine("Press <ENTER> to terminate service.");
  18:              Console.WriteLine();
  19:              Console.ReadLine();
  20:          }
  21:          #endregion

WSDL中的操作的名字,类型,活动和命名空间

WCF基于服务源代码中的命名类和属性定义生成一个向外抛出的文件。这个文件通过服务的MEX端点暴露,一般通过客户端在设计时以WSDL的形式使用。在客户端,WSDL然后使用它编写代码来构建匹配的消息格式进行与服务的通信。所以类名、方法名、参数名的命名与选择的影响远远超出服务本身的生命周期范围。

然而,通常在服务接口中暴露内部名称和细节是非常差的选择。例如,你也许有一个分配算法叫做BurgerMaster,而你希望将他以Resource的命名暴露在外部。或者也许受到编码标准的限制你必须决定以什么命名接口。幸运的是,你可以在服务端控制所有服务抛出的名字。通过修改[ServiceContract]、[OperationContract]和[ServiceBehavior]属性。下表列出了如何使用源代码中的WCF属性控制WSDL的格式。

WSDL标签

Wcf 属性

targetNamespace

默认是http://tempuri.org。可以使用代码中的[ServiceBehavior]属性修改。

wsdl:service 和 wsdl:definitions

[ServiceBehavior(Name=”myServiceName”)]

wsdl:prottype

[ServiceContract(Name=”myContractName”)]

wsdl:operation 和 soap:operation

[OperationContract(Name=”myOperationName”)]

xs:element

[MesageParameter(Name=”myParamName”)]

wsdl:input 和 wsdl:output

[OperationContract(Action=”myOperationAction”,ReplyAction=”myOperationReplyAction”)]

wsdl:Binding

使用和命名[DataContract]和[ServiceContract]属性

下面的例子使用WCF中的属性来重写默认生成的定义。

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Runtime.Serialization;
   5:  using System.ServiceModel;
   6:  using System.Text;
   7:   
   8:  namespace WcfWSDLServiceInIIS
   9:  {
  10:      
  11:      [ServiceContract(
  12:          Name = "MyBurgerMasterName", 
  13:          Namespace = "http://MyBurgerMasterNamespace")]
  14:      public interface IBurgerMasterService
  15:      {
  16:          [return: MessageParameter(Name="MyBurgerMasterStockPrice")]
  17:          [OperationContract(
  18:              Name = "MyGetBurgerMasterStockPrice", 
  19:              Action = "MyGetBurgerMasterStockPriceAction",
  20:              ReplyAction = "MyGetBurgerMasterStockPriceReplyAction")]
  21:          double GetStockPrice(string ticker);
  22:      }
  23:  }

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Runtime.Serialization;
   5:  using System.ServiceModel;
   6:  using System.Text;
   7:   
   8:  namespace WcfWSDLServiceInIIS
   9:  {    
  10:      [ServiceBehavior(Namespace=http://MyBurgerMasterService)]
public class BurgerMasterService : IBurgerMasterService
  11:      {
  12:          #region IBurgerMasterService Members
  13:   
  14:          double IBurgerMasterService.GetStockPrice(string ticker)
  15:          {
  16:              return 100.00;
  17:          }
  18:   
  19:          #endregion
  20:      }
  21:  }

svcutil.exe工具具有-t:metadata选项可以用来从服务端生成WSDL。或者,如果服务通过http绑定抛出一个MEX端口,WSDL可以IE使用基本的地址访问到。使用svcutil.exe访问或IE访问时的WSDL会有些不同,这些不同微不足道,只是与包相关。这两种情况下,下表下面显示了使用代码列表访问的WSDL。wsdl:portType,wsdl:operation,和wsdl:action名字都被代码控制了。注意,wsdl:portType的名字是MyBurgerMasterName,而不是默认的BurgerMaster。

  <?xml version="1.0" encoding="utf-8" ?>
- <wsdl:definitions name="BurgerMasterService" targetNamespace="http://MyBurgerMasterService"
... ...
... ...
xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex"><wsdl:import namespace="http://tempuri.org/" location="http://localhost:1877/BurgerMasterService.svc?wsdl=wsdl1" /> <wsdl:types />
- <wsdl:service name="BurgerMasterService">
- <wsdl:port name="WSHttpBinding_MyBurgerMasterName" binding="i0:WSHttpBinding_MyBurgerMasterName"><soap12:address location="http://localhost:1877/BurgerMasterService.svc" />
- <wsa10:EndpointReference><wsa10:Address>http://localhost:1877/BurgerMasterService.svc</wsa10:Address>
- <Identity xmlns="http://schemas.xmlsoap.org/ws/2006/02/addressingidentity"><Dns>localhost</Dns> </Identity></wsa10:EndpointReference></wsdl:port></wsdl:service></wsdl:definitions>

转载于:https://www.cnblogs.com/zhangdong/archive/2010/01/13/1646448.html

WCF中的服务契约(Continued)相关推荐

  1. 在WCF中实现双工通信(转载)

    首先声明此文章是转载博客园蒋老师之作:http://www.cnblogs.com/artech/archive/2007/03/02/661969.html 双工(Duplex)模式的消息交互方式体 ...

  2. [转载]我的WCF之旅(3):在WCF中实现双工通信

    http://www.cnblogs.com/artech/archive/2007/03/02/661969.html 双工(Duplex)模式的消息交换方式体现在消息交换过程中,参与的双方均可以向 ...

  3. 微服务治理实践:服务契约

    简介:随着微服务架构越来越流行,越来越多的公司使用微服务框架进行开发.甚至不止是公司,连笔者的研究生导师都要对实验室的Spring Boot工程项目转型使用微服务框架了. 本文是<微服务治理实践 ...

  4. WCF契约的简单介绍(服务契约 数据契约 消息契约)

    本篇博文只是简单说下WCF中的契约的种类.作用以及一些简单的代码示例.在WCF中契约分为服务契约.数据契约和消息契约.下面对这几种契约进行简单的介绍. 服务契约 服务契约描述了暴露给外部的类型(接口或 ...

  5. (2) 第二章 WCF服务与数据契约 服务契约详解(三)- [ServiceContract]特性

    本章节主要目的:了解[ServiceContract]特性 如前几章的进度,相信已经可以自己编写服务契约以及如何在客户端调用配置好的服务了. 本片主要讲解一下SerivceContract中的几个重要 ...

  6. 在WCF中使用Ninject轻量级IOC框架 之 SOAP风格服务

    最近学习MVC 看到很多文章都用了Ninject框架进行解耦,就考虑是否能用在平时写的WCF服务中,因为毕竟目前还是总要写服务的--蛋疼ing-- 传送门: Ninject框架官网: http://w ...

  7. (2) 第二章 WCF服务与数据契约 服务契约详解(二)- 如何引用WCF提供的服务

    本章节主要目的:掌握如何引用WCF提供的服务 下面来讲解一下如何引用WCF的服务,主要讲解2种方式: 1.Service References 操作步骤:1.在项目中右键鼠标->2.点击添加引用 ...

  8. .NET Framework 4.0 和 Dublin 中的 WCF 和 WF 服务 - z

    在 2008 年 10 月份召开的专业开发人员大会 (PDC) 上,Microsoft 发布了有关 Microsoft .NET Framework 4.0 中将要提供的大量改进的详细信息,尤其是在 ...

  9. [老老实实学WCF] 第三篇 在IIS中寄存服务

    老老实实学WCF 第三篇 在IIS中寄宿服务 通过前两篇的学习,我们了解了如何搭建一个最简单的WCF通信模型,包括定义和实现服务协定.配置服务.寄宿服务.通过添加服务引用的方式配置客户端并访问服务.我 ...

  10. WCF中的Stream操作

    WCF支持对Stream对象的操作,尤其对于传递size过大的消息而言,如要考虑传递消息的效率,WCF推荐通过Stream进行操作. 然而,WCF对于Stream操作规定了一些限制,在我们编写相关程序 ...

最新文章

  1. javascript常用验证大全
  2. java 登录 https_java – 如何在Web应用程序中实现HTTPS登录页面?
  3. 深度解读!时序数据库HiTSDB:分布式流式聚合引擎
  4. 【测试点分析】1072 开学寄语 (20分)_42行代码AC
  5. C#中split的用法
  6. 详解TCP协议的服务特点以及连接建立与终止的过程(俗称三次握手四次挥手)
  7. IPC--进程间通信六(消息队列)
  8. HCNA配置telnet远程管理
  9. 【转载】接口和抽象类的区别 --相信你看完不会再混淆了
  10. Android开发学习之卡片式布局的简单实现
  11. 显示2位小数 python3_python3+ 和 Python2+的一些区别
  12. VC调用3dmax自动化对象
  13. 立体栅格地图_高精地图之3D栅格地图的应用
  14. Retinex低光照图像增强
  15. 基于Java平台实现发送短信功能
  16. 顺丰快递查询api php,快递查询API接口_快递单号_申通顺丰数据接口 - 极速数据
  17. 如何解决搜狗浏览器自动填充
  18. 效果图什么网站赚零花钱_为什么你赚的钱少
  19. Orange Business Services 携手 Riverbed 将 SD-WAN 引入混合网络
  20. 关于航空障碍灯的介绍

热门文章

  1. 飞机坠落时应该主动抛弃油箱
  2. 管理感悟:需要什么样的技术文档
  3. 在控制台上看苹果手机的LOG
  4. win8系统服务器地址怎么查,win8查询服务器地址
  5. linux 系列:[所有相关文章链接]
  6. pxe dhcp offer之后没有_秒懂DHCP是什么
  7. 右键新建文件夹_教你修改Windows万年不变的黄色文件夹,让文件也不枯燥
  8. 当前最热门的编程语言python_2020年度最热门的编程语言盘点
  9. 使用Automake,Autoconf生成Makefile
  10. MySQL 创建数据表的命令行