Öbekleme Kanalı

ChunkingChannel örneği, özel bir protokolün veya katmanlanmış kanalın gelişigüzel büyük iletileri parçalama ve parçaları birleştirme işlemleri yapmak için nasıl kullanılabileceğini gösterir.

Windows Communication Foundation (WCF) kullanarak büyük iletiler gönderirken, genellikle bu iletileri arabelleğe almak için kullanılan bellek miktarını sınırlamak istenir. Olası çözümlerden biri ileti gövdesinin akışını yapmaktır (verilerin büyük bir kısmının gövdede olduğu varsayılarak). Ancak bazı protokoller mesajın tamamını arabelleğe almakı gerektirir. Güvenilir mesajlaşma ve güvenlik bu tür iki örnektir. Başka bir olası çözüm, büyük iletiyi öbek adı verilen daha küçük iletilere bölmek, bu öbekleri birer birer bir öbek göndermek ve büyük iletiyi alıcı tarafında yeniden oluşturmaktır. Uygulamanın kendisi bu öbekleme ve öbek kaldırma işlemini gerçekleştirebilir veya bunu yapmak için özel bir kanal kullanabilir.

Öbekleme her zaman yalnızca gönderilecek iletinin tamamı oluşturulduktan sonra kullanılmalıdır. Öbekleme kanalı her zaman bir güvenlik kanalının ve güvenilir bir oturum kanalının altına katmanlanmalıdır.

Not

Bu örnek için kurulum yordamı ve derleme yönergeleri bu konunun sonunda yer alır.

Kanal Varsayımlarını ve Sınırlamalarını Öbekleme

İleti Yapısı

Öbekleme kanalı, iletilerin öbeklenmesi için aşağıdaki ileti yapısını varsayar:

<soap:Envelope>
  <!-- headers -->
  <soap:Body>
    <operationElement>
      <paramElement>data to be chunked</paramElement>
    </operationElement>
  </soap:Body>
</soap:Envelope>

ServiceModel kullanılırken, 1 giriş parametresine sahip sözleşme işlemleri, giriş iletisi için bu ileti şekliyle uyumlu olur. Benzer şekilde, 1 çıkış parametresi veya dönüş değeri olan sözleşme işlemleri, çıkış iletisi için bu ileti şekliyle uyumludur. Aşağıda bu tür işlemlere örnekler verilmiştir:

[ServiceContract]
interface ITestService
{
    [OperationContract]
    Stream EchoStream(Stream stream);

    [OperationContract]
    Stream DownloadStream();

    [OperationContract(IsOneWay = true)]
    void UploadStream(Stream stream);
}

Oturumlar

Parçalama kanalı, iletilerin sıralı teslimatında (parçalar) tam olarak bir kez teslim edilmesini gerektirir. Bu, temel alınan kanal yığınının oturumlu olması gerektiği anlamına gelir. Oturumlar aktarım (örneğin, TCP aktarımı) veya oturumlu bir protokol kanalı (örneğin ReliableSession kanalı) tarafından sağlanabilir.

Asenkron Gönderim ve Alma

Zaman uyumsuz gönderme ve alma yöntemleri, öbekleme kanalı örneğinin bu sürümünde uygulanmaz.

Öbekleme Protokolü

Öbekleme kanalı, bir öbek dizisinin başlangıcını ve sonunu ve her öbek sırasını gösteren bir protokol tanımlar. Aşağıdaki üç örnek ileti, başlangıç, öbek ve bitiş iletilerini, her birinin önemli yönlerini açıklayan açıklamalarla gösterir.

İletiyi Başlat

<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing"
            xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Header>
<!--Original message action is replaced with a chunking-specific action. -->
    <a:Action s:mustUnderstand="1">http://samples.microsoft.com/chunkingAction</a:Action>
<!--
Original message is assigned a unique id that is transmitted
in a MessageId header. Note that this is different from the WS-Addressing MessageId header.
-->
    <MessageId s:mustUnderstand="1" xmlns="http://samples.microsoft.com/chunking">
53f183ee-04aa-44a0-b8d3-e45224563109
</MessageId>
<!--
ChunkingStart header signals the start of a chunked message.
-->
    <ChunkingStart s:mustUnderstand="1" i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://samples.microsoft.com/chunking" />
<!--
Original message action is transmitted in OriginalAction.
This is required to re-create the original message on the other side.
-->
    <OriginalAction xmlns="http://samples.microsoft.com/chunking">
http://tempuri.org/ITestService/EchoStream
    </OriginalAction>
   <!--
    All original message headers are included here.
   -->
  </s:Header>
  <s:Body>
<!--
Chunking assumes this structure of Body content:
<element>
  <childelement>large data to be chunked<childelement>
</element>
The start message contains just <element> and <childelement> without
the data to be chunked.
-->
    <EchoStream xmlns="http://tempuri.org/">
      <stream />
    </EchoStream>
  </s:Body>
</s:Envelope>

Parçalı Mesaj

<s:Envelope
  xmlns:a="http://www.w3.org/2005/08/addressing"
  xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Header>
   <!--
    All chunking protocol messages have this action.
   -->
    <a:Action s:mustUnderstand="1">
      http://samples.microsoft.com/chunkingAction
    </a:Action>
<!--
Same as MessageId in the start message. The GUID indicates which original message this chunk belongs to.
-->
    <MessageId s:mustUnderstand="1"
               xmlns="http://samples.microsoft.com/chunking">
      53f183ee-04aa-44a0-b8d3-e45224563109
    </MessageId>
<!--
The sequence number of the chunk.
This number restarts at 1 with each new sequence of chunks.
-->
    <ChunkNumber s:mustUnderstand="1"
                 xmlns="http://samples.microsoft.com/chunking">
      1096
    </ChunkNumber>
  </s:Header>
  <s:Body>
<!--
The chunked data is wrapped in a chunk element.
The encoding of this data (and the entire message)
depends on the encoder used. The chunking channel does not mandate an encoding.
-->
    <chunk xmlns="http://samples.microsoft.com/chunking">
kfSr2QcBlkHTvQ==
    </chunk>
  </s:Body>
</s:Envelope>

İletiyi Sonlandır

<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing"
            xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Header>
    <a:Action s:mustUnderstand="1">
      http://samples.microsoft.com/chunkingAction
    </a:Action>
<!--
Same as MessageId in the start message. The GUID indicates which original message this chunk belongs to.
-->
    <MessageId s:mustUnderstand="1"
               xmlns="http://samples.microsoft.com/chunking">
      53f183ee-04aa-44a0-b8d3-e45224563109
    </MessageId>
<!--
ChunkingEnd header signals the end of a chunk sequence.
-->
    <ChunkingEnd s:mustUnderstand="1" i:nil="true"
                 xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
                 xmlns="http://samples.microsoft.com/chunking" />
<!--
ChunkingEnd messages have a sequence number.
-->
    <ChunkNumber s:mustUnderstand="1"
                 xmlns="http://samples.microsoft.com/chunking">
      79
    </ChunkNumber>
  </s:Header>
  <s:Body>
<!--
The ChunkingEnd message has the same <element><childelement> structure
as the ChunkingStart message.
-->
    <EchoStream xmlns="http://tempuri.org/">
      <stream />
    </EchoStream>
  </s:Body>
</s:Envelope>

Parçalama Kanal Mimarisi

Öbekleme kanalı, yüksek düzeyde tipik kanal mimarisini izleyen bir IDuplexSessionChannel kanaldır. ChunkingBindingElement ve oluşturabilen ChunkingChannelFactory bir ChunkingChannelListenervardır. ChunkingChannelFactory, istendiğinde ChunkingChannel örneklerini oluşturur. ChunkingChannelListener, yeni bir iç kanal kabul edildiğinde ChunkingChannel örneklerini oluşturur. ChunkingChannel gönderme ve alma işinden sorumludur.

Bir sonraki düzeyde, ChunkingChannel öbekleme protokolünü uygulamak için birkaç bileşenden yararlanır. Gönderme tarafında kanal, gerçek öbekleme işlemini yapan ChunkingWriter adlı özel bir XmlDictionaryWriter kullanır. ChunkingWriter öbekleri göndermek için doğrudan iç kanalı kullanır. Özel XmlDictionaryWriter kullanmak, özgün iletinin büyük gövdesi yazılırken öbek göndermemizi sağlar. Bu, orijinal mesajın tamamının tamponlanmadığı anlamına gelir.

Parçalayıcı kanal gönderme mimarisini gösteren diyagram.

Alma tarafında, ChunkingChannel iletileri iç kanaldan çeker ve gelen öbeklerden özgün iletiyi yeniden oluşturan ChunkingReader adlı özel bir XmlDictionaryReader iletiye iletir. ChunkingChannelbunu ChunkingReader adlı Message özel ChunkingMessage bir uygulamada sarmalar ve bu iletiyi yukarıdaki katmana döndürür. ChunkingReader ve ChunkingMessage bileşimi, yukarıdaki katman tarafından okunmakta olan özgün ileti gövdesinin öbeklerini kaldırarak tamamını arabelleğe almak zorunda kalmadan işlem yapmamıza olanak tanır. ChunkingReader , gelen öbekleri en fazla yapılandırılabilir arabelleğe alınmış öbek sayısına kadar arabelleğe aldığı bir kuyruğa sahiptir. Okuyucu, bu maksimum sınıra ulaşıldığında iletilerin kuyruktan yukarıdaki katman tarafından (yani, yalnızca özgün ileti gövdesinden okuyarak) boşaltılmasını veya maksimum alma zaman aşımına ulaşılmasını bekler.

Parçalama kanalı alma mimarisini gösteren diyagram.

Öbekleme Programlama Modeli

Hizmet geliştiricileri, özniteliği sözleşmedeki işlemlere uygulayarak hangi iletilerin ChunkingBehavior öbekleneceğini belirtebilir. özniteliği, geliştiricinin öbeklemenin giriş iletisine mi, çıkış iletisine mi yoksa her ikisine mi uygulanacağını belirtmesine olanak tanıyan bir AppliesTo özellik sunar. Aşağıdaki örnekte özniteliğin kullanımı gösterilmektedir ChunkingBehavior :

[ServiceContract]
interface ITestService
{
    [OperationContract]
    [ChunkingBehavior(ChunkingAppliesTo.Both)]
    Stream EchoStream(Stream stream);

    [OperationContract]
    [ChunkingBehavior(ChunkingAppliesTo.OutMessage)]
    Stream DownloadStream();

    [OperationContract(IsOneWay=true)]
    [ChunkingBehavior(ChunkingAppliesTo.InMessage)]
    void UploadStream(Stream stream);

}

Bu programlama modelinden ChunkingBindingElement , öbeklenecek iletileri tanımlayan eylem URI'lerinin listesini derler. Her giden iletinin eylemi, iletinin öbeklenmesi mi yoksa doğrudan gönderilmesi mi gerektiğini belirlemek için bu listeyle karşılaştırılır.

Gönderme İşleminin Uygulanması

Yüksek düzeyde, Gönder işlemi önce giden iletinin öbeklenip öbeklenmemesi gerektiğini denetler ve değilse, iletiyi doğrudan iç kanalı kullanarak gönderir.

İletinin öbeklenmesi gerekiyorsa, yeni bir ChunkingWriter oluşturur ve bunu ChunkingWriter kullanarak giden iletide WriteBodyContents çağırır. ardından ChunkingWriter , ileti öbeklemesi yapar (özgün ileti üst bilgilerini başlangıç öbek iletisine kopyalama dahil) ve iç kanalı kullanarak öbekler gönderir.

Dikkate değer birkaç ayrıntı:

  • İlk çağrıları ThrowIfDisposedOrNotOpened göndererek CommunicationState açıldığından emin olun.

  • Gönderme eşitlenir, böylece her oturum için aynı anda yalnızca bir ileti gönderilebilir. Öbeklenmiş bir ileti gönderilirken sıfırlanan sendingDone adlı bir ManualResetEvent vardır. Son parça mesajı gönderildikten sonra bu olay tetiklenir. Send yöntemi, giden iletiyi göndermeye çalışmadan önce bu olayın ayarlanmasını bekler.

  • Send işlemi, gönderim sırasında eşzamanlı durum değişikliklerini önlemek için CommunicationObject.ThisLock öğesini kilitler. CommunicationObject Durumlar ve durum makinesi hakkında CommunicationObject daha fazla bilgi için belgelere bakın.

  • Gönder'e geçirilen zaman aşımı, tüm öbeklerin gönderilmesini içeren gönderme işleminin tamamı için zaman aşımı olarak kullanılır.

  • Özgün ileti gövdesinin tamamını arabelleğe almaktan kaçınmak için özel XmlDictionaryWriter tasarım seçildi. Eğer XmlDictionaryReader'i tüm beden üzerinde kullanırsak, tüm beden arabelleğe alınır. Bunun yerine, öğesine XmlDictionaryWriter geçirilmiş bir özel message.WriteBodyContents öğemiz var. İleti yazıcıda WriteBase64'i çağırırken, yazıcı öbekleri iletiler halinde paketler ve iç kanalı kullanarak gönderir. WriteBase64, öbek gönderilene kadar bekler.

Alma İşleminin Uygulaması

Yüksek düzeyde bakıldığında, Receive işlemi ilk olarak gelen iletinin null olmadığını ve işleminin ChunkingAction olduğunu denetler. Her iki ölçüte de uymazsa, ileti Alış'tan değiştirilmeden döndürülür. Aksi takdirde, Receive yeni bir ChunkingReader oluşturur ve bunu GetNewChunkingMessage çağırarak yeni bir ChunkingMessage ile sarar. Yeni ChunkingMessage öğesini döndürmeden önce, Receive, bir iş parçacığı havuzu iş parçacığı kullanarak, ReceiveChunkLoop'yi bir döngü içinde çağırır ve öbekleri, son öbek mesajı alınana ya da alma zaman aşımına ulaşana kadar ChunkingReader'ye iletir.

Dikkate değer birkaç ayrıntı:

  • Al gibi, Al ilk olarak ThrowIfDisposedOrNotOpened çağrısını yapar ve CommunicationState'in Açık olduğundan emin olur.

  • Oturumdan aynı anda yalnızca bir ileti alınabilmesi için alma işlemi de senkronize edilir. Bu özellikle önemlidir çünkü bir başlangıç öbek iletisi alındıktan sonra, bir son öbek iletisi alınana kadar sonraki tüm alınan iletilerin bu yeni öbek dizisi içinde öbekler olması beklenir. Alma, öbekleri kaldırılmakta olan iletiye ait tüm öbekler alınana kadar iç kanaldan iletileri çekemez. Bunu gerçekleştirmek için, Receive, currentMessageCompleted adlı bir ManualResetEvent kullanır. Bu, bitiş parça mesajı alındığında ayarlanır ve yeni bir başlangıç parça mesajı alındığında sıfırlanır.

  • Gönder'in aksine Alma, alma sırasında eşitlenmiş durum geçişlerini engellemez. Örneğin, Close işlemi alınma süreci devam ederken çağrılabilir ve orijinal iletinin bekleyen alma işlemi tamamlanana veya belirtilen zaman aşımı değerine ulaşılana kadar beklemeye devam eder.

  • Alma işlemine geçirilen zaman aşımı, tüm öbekleri almayı da içeren alma işleminin tamamı için zaman aşımı olarak kullanılır.

  • tr-TR: İletiyi kullanan katman, ileti gövdesini gelen parça mesajların hızından daha düşük bir hızda tüketiyorsa, ChunkingReader bu gelen parçaları ChunkingBindingElement.MaxBufferedChunks tarafından belirtilen sınıra kadar arabelleğe alır. Bu sınıra ulaşıldıktan sonra, arabelleğe alınan bir öbek tüketilene veya alma zaman aşımına ulaşılana kadar alt katmandan başka öbek çekilmez.

CommunicationObject Geçersiz Kılmaları

OnOpen

, iç kanalı açmak için arar.

OnClose

OnClose önce stopReceive öğesini true olarak ayarlayarak beklemede olan ReceiveChunkLoop'in durması için sinyal verir. Ardından ReceiveChunkLoop durdurulduğunda ayarlanan receiveStoppedManualResetEvent öğesini bekler. ReceiveChunkLoop belirtilen zaman aşımı içinde durursa, OnClose kalan zaman aşımıyla birlikte innerChannel.Close'yi çağırır.

OnAbort

OnAbort iç kanalı durdurmak için innerChannel.Abort'i arar. Eğer bekleyen bir ReceiveChunkLoop varsa, bu beklemeden kaynaklanan innerChannel.Receive çağrısından bir istisna alır.

OnFaulted

ChunkingChannel kanal hatalı olduğunda özel davranış gerektirmez, bu nedenle OnFaulted geçersiz kılınmaz.

Channel Factory'nin Uygulanması

ChunkingChannelFactory, ChunkingDuplexSessionChannel örneklerinin oluşturulmasından ve durum geçişlerinin iç kanal fabrikasına basamaklanmasından sorumludur.

OnCreateChannel, iç kanal oluşturmak için iç kanal fabrikasını kullanır. Ardından, bu iç kanala, öbeklenecek ileti eylemlerinin listesi ve alma sırasında arabelleğe alınacak en fazla öbek sayısıyla birlikte yeni ChunkingDuplexSessionChannel bir geçiş oluşturur. Parçalara ayrılacak ileti eylemlerinin listesi ve en fazla arabelleğe alınacak öbek sayısı, ChunkingChannelFactory'nin oluşturucusunda geçirilen iki parametredir. üzerindeki ChunkingBindingElement bölümünde bu değerlerin nereden geldiği açıklanmaktadır.

OnOpen, OnClose, OnAbort ve asenkron eşdeğerleri, iç kanal fabrikasında ilgili durum geçiş yöntemini çağırır.

Kanal Dinleyicisinin Uygulanması

ChunkingChannelListener, bir iç kanal dinleyicisinin etrafındaki bir kapsayıcıdır. Ana işlevi, bu iç kanal dinleyicisine yapılan temsilci çağrılarının yanı sıra, iç kanal dinleyicisinden kabul edilen kanalların çevresinde yenileri ChunkingDuplexSessionChannels kaydırmaktır. Bu işlem OnAcceptChannel ve OnEndAcceptChannel içinde yapılır. Yeni oluşturulan ChunkingDuplexSessionChannel , daha önce açıklanan diğer parametrelerle birlikte iç kanala geçirilir.

Bağlama Öğesini ve Bağlantıyı Uygulama

ChunkingBindingElement, ChunkingChannelFactory ve ChunkingChannelListener oluşturmakla sorumludur. ChunkingBindingElement kontrol eder: CanBuildChannelFactory<T> ve CanBuildChannelListener<T>'nin, IDuplexSessionChannel türünde olup olmadığını (öbekleme kanalı tarafından desteklenen tek kanal) ve bağlamadaki diğer bağlama öğelerinin bu kanal türünü destekleyip desteklemediğini.

BuildChannelFactory <T> önce istenen kanal türünün oluşturulup oluşturulamayacağını denetler ve ardından bölünecek mesaj eylemlerinin listesini alır. Daha fazla bilgi için aşağıdaki bölüme bakın. Ardından, iç kanal fabrikasını (öğesinden context.BuildInnerChannelFactory<IDuplexSessionChannel> döndürüldüğü gibi), ileti eylemleri listesini ve arabelleğe alınacak en fazla öbek sayısını geçirerek yeni bir ChunkingChannelFactory oluşturur. Maksimum parça sayısı, ChunkingBindingElement tarafından kullanıma sunulan MaxBufferedChunks adlı bir özellikten gelir.

BuildChannelListener<T>, ChunkingChannelListener'i oluşturmak ve iç kanal dinleyicisini geçirmek için benzer bir uygulamaya sahiptir.

Bu örnekte adlı TcpChunkingBindingbir örnek bağlama vardır. Bu bağlama iki bağlama öğesinden oluşur: TcpTransportBindingElement ve ChunkingBindingElement. Bağlama, MaxBufferedChunks özelliğini kullanıma açmanın yanı sıra, TcpTransportBindingElement gibi bazı MaxReceivedMessageSize özelliklerini de ayarlar (üst bilgiler için ChunkingUtils.ChunkSize + 100 KB bayt olarak ayarlar).

TcpChunkingBinding ayrıca IBindingRuntimePreferences uygular ve yalnızca zaman uyumlu Alma çağrılarının uygulandığını belirten ReceiveSynchronously yönteminden true değerini döndürür.

Bölümlenecek iletileri belirleme

Öbekleme kanalı yalnızca özniteliği aracılığıyla ChunkingBehavior tanımlanan iletileri öbekler. ChunkingBehavior sınıfı, IOperationBehavior uygular ve AddBindingParameter yöntemini çağırarak uygulanır. Bu yöntemdeChunkingBehavior, hangi iletilerin öbeklenmesi gerektiğini belirlemek için özelliğinin AppliesTo (InMessageOutMessageveya her ikisinin) değerini inceler. Ardından bu iletilerin her birinin eylemini OperationDescription üzerindeki İletiler koleksiyonundan alır ve ChunkingBindingParameter içinde yer alan bir dize koleksiyonuna ekler. Ardından ChunkingBindingParameter bunu, sağlanan BindingParameterCollection öğesine ekler.

Bu BindingParameterCollection, bağlamadaki her bağlama öğesine, bağlama öğesi kanal fabrikasını veya kanal dinleyicisini oluştururken BindingContext içinde geçirilir. ChunkingBindingElement'nin BuildChannelFactory<T> ve BuildChannelListener<T> uygulaması bu ChunkingBindingParameteryı BindingContext'lerin içinden çekip çıkarırBindingParameterCollection. ChunkingBindingParameter içinde yer alan eylemlerin koleksiyonu daha sonra ChunkingChannelFactory veya ChunkingChannelListener öğesine geçirilir ve ardından ChunkingDuplexSessionChannel öğesine aktarılır.

Örneği Çalıştırma

Örneği ayarlamak, derlemek ve çalıştırmak için

  1. Aşağıdaki komutu kullanarak ASP.NET 4.0'ı yükleyin.

    %windir%\Microsoft.NET\Framework\v4.0.XXXXX\aspnet_regiis.exe /i /enable
    
  2. Windows Communication Foundation Örnekleri için Tek Seferlik Kurulum Yordamı'nı gerçekleştirdiğinizden emin olun.

  3. Çözümü oluşturmak için Windows Communication Foundation Örnekleri Oluşturma başlığındaki yönergeleri izleyin.

  4. Örneği tek veya makineler arası bir yapılandırmada çalıştırmak için Windows Communication Foundation Örneklerini Çalıştırma başlığındaki yönergeleri izleyin.

  5. önce Service.exe çalıştırın, ardından Client.exe çalıştırın ve çıkış için her iki konsol penceresini de izleyin.

Örnek çalıştırılırken aşağıdaki çıkış beklenir.

İstemci:

Press enter when service is available

 > Sent chunk 1 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10
 > Sent chunk 2 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10
 > Sent chunk 3 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10
 > Sent chunk 4 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10
 > Sent chunk 5 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10
 > Sent chunk 6 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10
 > Sent chunk 7 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10
 > Sent chunk 8 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10
 > Sent chunk 9 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10
 > Sent chunk 10 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10
 < Received chunk 1 of message 5b226ad5-c088-4988-b737-6a565e0563dd
 < Received chunk 2 of message 5b226ad5-c088-4988-b737-6a565e0563dd
 < Received chunk 3 of message 5b226ad5-c088-4988-b737-6a565e0563dd
 < Received chunk 4 of message 5b226ad5-c088-4988-b737-6a565e0563dd
 < Received chunk 5 of message 5b226ad5-c088-4988-b737-6a565e0563dd
 < Received chunk 6 of message 5b226ad5-c088-4988-b737-6a565e0563dd
 < Received chunk 7 of message 5b226ad5-c088-4988-b737-6a565e0563dd
 < Received chunk 8 of message 5b226ad5-c088-4988-b737-6a565e0563dd
 < Received chunk 9 of message 5b226ad5-c088-4988-b737-6a565e0563dd
 < Received chunk 10 of message 5b226ad5-c088-4988-b737-6a565e0563dd

Sunucu:

Service started, press enter to exit
 < Received chunk 1 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10
 < Received chunk 2 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10
 < Received chunk 3 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10
 < Received chunk 4 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10
 < Received chunk 5 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10
 < Received chunk 6 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10
 < Received chunk 7 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10
 < Received chunk 8 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10
 < Received chunk 9 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10
 < Received chunk 10 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10
 > Sent chunk 1 of message 5b226ad5-c088-4988-b737-6a565e0563dd
 > Sent chunk 2 of message 5b226ad5-c088-4988-b737-6a565e0563dd
 > Sent chunk 3 of message 5b226ad5-c088-4988-b737-6a565e0563dd
 > Sent chunk 4 of message 5b226ad5-c088-4988-b737-6a565e0563dd
 > Sent chunk 5 of message 5b226ad5-c088-4988-b737-6a565e0563dd
 > Sent chunk 6 of message 5b226ad5-c088-4988-b737-6a565e0563dd
 > Sent chunk 7 of message 5b226ad5-c088-4988-b737-6a565e0563dd
 > Sent chunk 8 of message 5b226ad5-c088-4988-b737-6a565e0563dd
 > Sent chunk 9 of message 5b226ad5-c088-4988-b737-6a565e0563dd
 > Sent chunk 10 of message 5b226ad5-c088-4988-b737-6a565e0563dd