PerCall 與 PerSession 在 Tcp 與 Http 傳輸模式下的差異性

  • 2709
  • 0
  • wcf
  • 2010-11-20

PerCall 與 PerSession 在 Tcp 與 Http 傳輸模式下的差異性

Tcp 與 Http 兩種傳輸模式

應該是WCF中最常見到的兩種傳輸模式

Http 是以前 WebService 的延伸

所以傳輸方式是一次性的連接

而Tcp傳輸的方式則是使用Binary

 

另外 ServiceBehavior 提供了三種Server端實體建立的模式

分別是 PreCall, PreSession 還有 Signle

其中 Single 通常使用在比較特殊的用途

所以我們不在這邊討論

PreCall 則是每次呼叫的時候在Server端建立一個實體

呼叫完畢便等待回收

而PreSession 則是在Client連線的時候建立一個實體在Server

直到連線結束才釋放掉

 

我在範例程式中

將一個大小約1MB左右的檔案

以每100Byte為單位進行切割

然後由Client持續對Server發送

藉此來觀察WCF的行為模式和傳輸效率

以下為程式碼範例

 

WCF 要使用的合約:

	namespace WCF_Lib
{
    [ServiceContract]
    public interface ISendData
    {
        [OperationContract(IsOneWay = true)]
        void Send(FileData mFileData_);
    }


    [DataContract]
    public class FileData
    {
        [DataMember]
        public readonly byte[] byData;

        [DataMember]
        public readonly string szDataName;

        [DataMember]
        public readonly bool bFinish;

        [DataMember]
        public readonly int iSequence;

        public FileData(string szDataName_, byte[] byData_, int iLength_, int iSequence_, bool bFinish_)
        {
            this.szDataName = szDataName_;
            this.bFinish = bFinish_;
            this.iSequence = iSequence_;
            
            byData = new byte[iLength_];
            Array.Copy(byData_, byData, iLength_);
        }
    }
    
    
    //[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class SendDataClass : ISendData
    {
        private static FileStream mWriteFile = null;
        private static DateTime dtStart;
        
        public SendDataClass()
        {
            Console.WriteLine("Created instance {0}", DateTime.Now);
        }


        public void Send(FileData mFileData_)
        {
            if (mWriteFile == null)
            {
                mWriteFile = new FileStream(mFileData_.szDataName, FileMode.Create);
                dtStart = DateTime.Now;
            }


            Console.WriteLine("Received sequence {0}", mFileData_.iSequence);

            mWriteFile.Write(mFileData_.byData, 0, mFileData_.byData.Length);


            if (mFileData_.bFinish)
            {
                mWriteFile.Close();
                mWriteFile = null;

                DateTime dtEnd = DateTime.Now;
                TimeSpan tsTime = dtEnd - dtStart;

                Console.WriteLine("Started {0}", dtStart);
                Console.WriteLine("Ended {0}", dtEnd);
                Console.WriteLine("Spant {0}", tsTime.TotalSeconds);
            }
        }
    }
}
 

Client的程式碼:

	namespace Client
{
    class ClientProgram
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Started {0}", DateTime.Now);

            using (ChannelFactory<ISendData> mChannelFactory = new ChannelFactory<ISendData>("WCF_Training"))
            {
                ISendData mSendDataChanel = mChannelFactory.CreateChannel();


                const string szFileName = "TestFile.jpg";
                FileStream mOpenFile = new FileStream(szFileName, FileMode.Open);


                int iMaxLen = 100; // The size of each cutting
                int iOffset = -1;
                int iSequence = 1;
                bool bFinal = false;
                byte[] byBuff = new byte[iMaxLen];
                
                do
                {
                    if (mOpenFile.Length <= iMaxLen*iSequence)
                        bFinal = true;
                    
                    iOffset = mOpenFile.Read(byBuff, 0, iMaxLen);

                    mSendDataChanel.Send(new FileData(szFileName, byBuff, iOffset, iSequence++, bFinal));                
                
                }while(!bFinal);


                mOpenFile.Close();

                mChannelFactory.Close();
            }

            Console.WriteLine("Ended {0}", DateTime.Now);
            Console.ReadLine();
        }
    }
}
 
Server的程式碼:
	namespace Server
{
    class ServerProgram
    {
        static void Main(string[] args)
        {
            using (ServiceHost mHost = new ServiceHost(typeof(SendDataClass)))
            {
                mHost.Open();

                Console.WriteLine("Service started");

                Console.ReadLine();

                mHost.Close();
            }
        }
    }
}

 

藉由觀察上面程式碼的輸出結果

我們將可以發現在tcp模式下面

如果你使用的是 PreCall

每次要傳送資料時

整個 SendDataClass 的建構式都會被呼叫一次

可是在PreSession的時候

只有第一次建構式會被呼叫

所以理所當然的 PreSession 的傳輸效率

遠遠的大於 PreCall

 

但是使用Http傳輸的時候

不管你使用的是PreCall還是PreSession

建構式還是每次都會被呼叫

所以基本上效率是差不多的

 

以下是傳輸的時間數據

每種方式都進行五次取其平均值

image