Pull to refresh

IPC: сокеты против именованных каналов

Reading time 6 min
Views 31K
Абсолютные числа большого смысла не имеют, но как сравнение информация представляет некоторую ценность

Условия


Windows 7 x64 с обновлениями
AMD Athlon X2 4600+ (2.41ГГц)
DDR2 2Гб
.Net Framework 3.5, классы из FCL.
Два 64-битных процесса без дополнительных привилегий.
Антивирус Касперского выключен. С ним результаты сокетов существенно хуже.
Сокеты и именованные каналы в асинхронном режиме.
Размеры буферов подбирались оптимальные, эксперементально для каждого вида IPC.

Результаты


Сокеты
Скорость односторонней передачи — 160 мегабайт в секунду (105 с антивирусом)
Загрузка процессора — 90%, из них примерно 2/3 в ядре
Оперативная память — 4-5 мегабайт на процесс, со временем не росла

Именованные каналы
Скорость односторонней передачи — 755 мегабайт в секунду (антивирус не влияет)
Загрузка процессора — 80%, из них примерно 2/3 в ядре
Оперативная память — 4-5 мегабайт на процесс, со временем не росла

Исходный код


Сокеты
using System;
using System.IO.Pipes;
using System.Net;
using System.Net.Sockets;

namespace Server
{
  public static class Program
  {
    private static byte[] buffer = new byte[512 * 1024];

    private static void OnSocketSend(IAsyncResult ar)
    {
      Socket client = (Socket)ar.AsyncState;

      client.EndSend(ar);
      client.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, OnSocketSend, client);
    }

    public static void Main(string[] args)
    {
      Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

      server.Bind(new IPEndPoint(IPAddress.Loopback, 5000));
      server.Listen(10);

      while (true)
      {
        Socket client = server.Accept();

        client.SendBufferSize = 2 * buffer.Length;
        client.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, OnSocketSend, client);

        Console.WriteLine("CONNECTED");
      }
    }
  }
}


* This source code was highlighted with Source Code Highlighter.


using System;
using System.Diagnostics;
using System.IO.Pipes;
using System.Net;
using System.Net.Sockets;

namespace Client
{
  public static class Program
  {
    private static byte[] buffer = new byte[512 * 1024];
    private static Stopwatch watch = new Stopwatch();
    private static long traffic = 0;
    private static int step = 0;

    private static void OnSocketReceive(IAsyncResult ar)
    {
      Socket client = (Socket)ar.AsyncState;

      traffic += client.EndReceive(ar);
      step++;

      if ((step % 1000) == 0)
      {
        watch.Stop();

        Console.WriteLine(
          "{0} MB/s",
          (1000 * (traffic >> 20)) / watch.ElapsedMilliseconds);

        watch.Start();
      }

      client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, OnSocketReceive, client);
    }

    public static void Main(string[] args)
    {
      Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

      client.ReceiveBufferSize = 2 * buffer.Length;
      client.Connect(new IPEndPoint(IPAddress.Loopback, 5000));

      watch.Start();

      client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, OnSocketReceive, client);

      Console.WriteLine("CONNECTED");
      Console.ReadLine();
    }
  }
}


* This source code was highlighted with Source Code Highlighter.

Именованные каналы

using System;
using System.IO.Pipes;
using System.Net;
using System.Net.Sockets;

namespace Server
{
  public static class Program
  {
    private static byte[] buffer = new byte[256 * 1024];

    private static void OnPipeSend(IAsyncResult ar)
    {
      NamedPipeServerStream server = (NamedPipeServerStream)ar.AsyncState;

      server.EndWrite(ar);
      server.BeginWrite(buffer, 0, buffer.Length, OnPipeSend, server);
    }

    public static void Main(string[] args)
    {
      NamedPipeServerStream server = new NamedPipeServerStream("TestPipe", PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, 1024 * 1024, 1024 * 1024);

      server.WaitForConnection();
      server.BeginWrite(buffer, 0, buffer.Length, OnPipeSend, server);

      Console.WriteLine("CONNECTED");
      Console.ReadLine();
    }
  }
}


* This source code was highlighted with Source Code Highlighter.


using System;
using System.Diagnostics;
using System.IO.Pipes;
using System.Net;
using System.Net.Sockets;

namespace Client
{
  public static class Program
  {
    private static byte[] buffer = new byte[256 * 1024];
    private static Stopwatch watch = new Stopwatch();
    private static long traffic = 0;
    private static int step = 0;

    private static void OnPipeReceive(IAsyncResult ar)
    {
      NamedPipeClientStream client = (NamedPipeClientStream)ar.AsyncState;

      traffic += client.EndRead(ar);
      step++;

      if ((step % 1000) == 0)
      {
        watch.Stop();

        Console.WriteLine(
          "{0} MB/s",
          (1000 * (traffic >> 20)) / watch.ElapsedMilliseconds);

        watch.Start();
      }

      client.BeginRead(buffer, 0, buffer.Length, OnPipeReceive, client);
    }

    public static void Main(string[] args)
    {
      NamedPipeClientStream client = new NamedPipeClientStream(".", "TestPipe", PipeDirection.InOut, PipeOptions.Asynchronous);

      client.Connect();

      watch.Start();

      client.BeginRead(buffer, 0, buffer.Length, OnPipeReceive, client);

      Console.WriteLine("CONNECTED");
      Console.ReadLine();
    }
  }
}


* This source code was highlighted with Source Code Highlighter.
Tags:
Hubs:
+22
Comments 76
Comments Comments 76

Articles