環境.net4.0 使用NetTcpBinding
概要
執行個體管理可以理解為服端怎麼管理(建立與銷毀)Service 類的執行個體
而並發可以理解為WCF架構在收到用戶端請求後針對目標Service執行個體的派發行為,Single表現為如果Service已經在處理請求了,那麼新的請求(注意是針對同一個Service執行個體的)將排隊,如果是Mutiple那麼請求將立即執行,其實質是請求的處理基於同一個Service執行個體的鎖定同步行為。
進一步說明,WCF針對請求的處理是基於池線程的,當使用NetTcp的同個proxy(對應物理上的一Tcp連結)發出多個請求時,如果伺服器使用的是PerCall+Single組合,那麼該條TCP連結的請求將串列華處理(無法說是分配一個固定線程處理,因觀察到同個proxy,50個並發請在兩個線程上運行--指更換過一次線程)。
//==========測試代碼服務端=============
View Code
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel;using System.Threading;namespace WCFServer{ class Program { static void Main(string[] args) { var timer = new Timer((o) => { GC.Collect(); }, null, 0, 100); using(ServiceHost host=new ServiceHost(typeof(CalculatorService))) { host.AddServiceEndpoint(typeof(ICalculator), new NetTcpBinding(), "net.tcp://192.168.1.31:8888/CalculatorService"); host.Opened += (s,e) => { Console.WriteLine("服務啟動!"); }; host.Open(); Console.Read(); } } } [ServiceContract] public interface ICalculator { [OperationContract] int Add(int x, int y); } [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single,ConcurrencyMode=ConcurrencyMode.Single)] public class CalculatorService : ICalculator,IDisposable { public CalculatorService() { Console.WriteLine( AddThreadMsg( "Instantiated!")); } public int Add(int x, int y) { Console.WriteLine(AddThreadMsg( string.Format("index:{0}, Time:{1}, Operation method is invoked.",x,DateTime.Now))); Thread.Sleep(1000); return x + y; } ~CalculatorService() { Console.WriteLine(AddThreadMsg( "Finalized!")); } public void Dispose() { Console.WriteLine(AddThreadMsg( "Dispose!")); } private string AddThreadMsg(string msg) { return msg + ",ThreadId:" + Thread.CurrentThread.ManagedThreadId; } }}
//==========測試代碼用戶端=============
View Code
static void Main(string[] args) { using (ChannelFactory<ICalculator> channelFac = new ChannelFactory<ICalculator>(new NetTcpBinding(), "net.tcp://192.168.1.31:8888/CalculatorService")) { var proxy = channelFac.CreateChannel(); if (null != proxy as ICommunicationObject) { (proxy as ICommunicationObject).Open(); } Random rnd=new Random(); for (int i = 1; i < 50; i++) { var index = i; Thread t=new Thread(()=>{ try { Thread.Sleep(rnd.Next(100, 10000)); Console.WriteLine(string.Format("{3}:{0}+{1}={2}", index, 2, proxy.Add(index, 2), index)); //(proxy as ICommunicationObject).Close(); } catch (Exception ex) { Console.WriteLine(string.Format("Error-{0}:{1}", index, ex.Message)); } }); t.Start(); } Console.Read(); } Console.WriteLine("完成"); Console.Read(); } }
//說明
1.在使用NetTcpBinding時,一個用戶端proxy跟一條串連對應(可以通過建立多個proxy類比多個用戶端),在調用open後,可以通過netstat命令看到建立的TCP 串連。
2.當使用多線程類比多個並發的連結時(proxy),伺服器預設只能並行的接收11個串連,這個跟socket編程時監聽連接埠允許並發的連結數設定一致。
3.PerCall + Mutiple時,建立一個proxy在未開啟的情況下在多個線程中調用,proxy會根據調用先後對這些調用請求進行串列華處理。
4.PerCall + Mutiple時,建立多個proxy進行並發調用,伺服器表現是平行處理請求。
5.PerCall + Single時,建立多個proxy並發請求時,伺服器呈現平行處理,而單個proxy並發請求時,伺服器呈現串列處理,當把NetTcpBingding換成BasicHttpBinding時伺服器又變為出平行處理,不過可以通過netstat看到,使用http協議後單個proxy的並發調用實際上是建立了多個tcp串連的,
可見PerCall +Single時針對同個連結發來的請求是串列處理的
參考:
http://www.cnblogs.com/tyb1222/archive/2012/05/23/2515535.html