WebSockets on Windows Server 2012 with WCF 4.5 after TuneUp

Hi, today I try to tune up my last example with very trivial way with buffer. Now my example is much faster. Buffer for sending data usual have array form. In my example I change “double value” into “params double[] values” parameter. With that modification older implementation can still works just fine, but when someone wants to use buffered array values it is possible now in elegant way.

image

Do did so by changing a little bit a Contracts.cs (WebSocketsSandbox.Contracts)

namespace WebSocketsSandbox.Contracts
{
  using System.ServiceModel;
  using System.Threading.Tasks;

  [ServiceContract]
  public interface IClientCallback {
    [OperationContract(IsOneWay = true)]
    Task SendValues(string code, params double[] values);
  }

  [ServiceContract(CallbackContract = typeof(IClientCallback), SessionMode = SessionMode.Required)]
  public interface ISendValuesService {
    [OperationContract(IsOneWay = true)]
    Task StartSendingValues();
  }
}

I changed a little bit Server.cs (WebSocketsSandbox.Server)

namespace WebSocketsSandbox.Server
{
  using System;
  using System.Configuration;
  using System.ServiceModel;
  using System.ServiceModel.Channels;
  using System.ServiceModel.Configuration;
  using System.ServiceModel.Description;
  using System.Threading.Tasks;
  using WebSocketsSandbox.Contracts;

  class Server {
    static void Main(string[] args) {
      ConfigurationManager.AppSettings
        ["aspnet:UseTaskFriendlySynchronizationContext"] = "true";

      var mapping = new System.ServiceModel.Configuration.ProtocolMappingElementCollection();
      mapping.Add(
        element: new ProtocolMappingElement(
          schemeType: "http",
          binding: "netHttpBinding",
          bindingConfiguration: "default"));
      mapping.Add(
        element: new ProtocolMappingElement(
          schemeType: "https",
          binding: "netHttpsBinding",
          bindingConfiguration: "default"));

      ServiceHost serviceHost = null;

      try {
        string addressStr = "http://localhost:27272/WebSocketsServiceValues";

        var binding = new NetHttpBinding(
          securityMode: BasicHttpSecurityMode.None,
          reliableSessionEnabled: true);

        var addressUri = new Uri(uriString: addressStr);

        serviceHost = new ServiceHost(
          serviceType: typeof(SendValuesService),
          baseAddresses: addressUri);

        var endpoint = serviceHost.AddServiceEndpoint(
          implementedContract: typeof(ISendValuesService),
          binding: binding,
          address: addressUri);

        serviceHost.Open();

        Console.WriteLine(
          "WebSocketsServiceValues service is running, press any key to close...");
        Console.ReadKey();

      }
      catch (Exception ex) {
        Console.WriteLine(ex.ToString());
      }
      finally {
        serviceHost.Close();
      }
    }
  }

  [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
  class SendValuesService : ISendValuesService {
    public async Task StartSendingValues() {
      var callback = OperationContext.Current.GetCallbackChannel<IClientCallback>();
      var random = new Random();
      var count = 0;

      while (((IChannel)callback).State == CommunicationState.Opened) {
        var values = new double[250];
        for (var i = 0; i < values.Length; ++i)
          values[i] = random.NextDouble();
        await callback.SendValues("WebSocketsServiceValues", values);
        if ((count+=values.Length) == 1000000)
          break;
      }
    }
  }
}

And a Client.cs (WebSocketsSandbox.Client) file as well.

namespace WebSocketsSandbox.Client
{
  using System;
  using System.Collections.Generic;
  using System.ServiceModel;
  using System.ServiceModel.Description;
  using System.Threading;
  using System.Threading.Tasks;
  using WebSocketsSandbox.Contracts;

  class Client {
    static void Main(string[] args) {
      var context = new InstanceContext(
        implementation: new CallbackHandler());

      var binding = new NetHttpBinding(
        securityMode: BasicHttpSecurityMode.None,
        reliableSessionEnabled: true);

      var address = new EndpointAddress(
         uri: "http://localhost:27272/WebSocketsServiceValues");

      var channelFactory = new DuplexChannelFactory<ISendValuesService>(
        callbackInstance: context,
        binding: binding,
        remoteAddress: address);

      var client = channelFactory.CreateChannel(address: address);

      client.StartSendingValues();

      Console.WriteLine(
        "WebSocketsServiceValues client is running, press any key to close...");
      Console.ReadKey();
    }
  }

  class CallbackHandler : IClientCallback {
    int count = 0;

    public async Task SendValues(string code, params double[] values) {
      Interlocked.Exchange(ref count, count + values.Length);
      if (count % 1000 == 0)
        Console.WriteLine("{0}, {1}",
          DateTime.UtcNow.ToString("HH:mm:ss.ffff"),
          count);
    }
  }
}

Now I think solution is much more flexible and tune up in elegant way. You can find entire solution here. And at the end I will show you a performance of the solutions after tuning up.

image

It is much better isn’t?

P ;).

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.