如何在C#套接字服务器测试中正确模拟高延迟?

时间:2010-07-09 13:29:19

标签: c# .net testing sockets

我有一个直接使用'System.Net.Sockets.Socket'进行网络通信的类,目前我使用以下两个接口来破坏对Socket类的依赖:

public interface ISocketListener
    {
        void Listen(int backlog);

        ISocket Accept();

        void Bind(EndPoint endpoint);               
    }

public interface ISocket
    {
        void Connect (EndPoint ep);

        Stream CommunicationStream { get; }

        void Close();

        void Close(int timeout);

        void Shutdown();
    }

在生产实现中,我只是将所有方法调用重定向到私有Socket对象。在测试环境中,我使用MemoryStream作为套接字之间的通信“管道”。   由于我对这个主题没什么经验,所以在编写测试时我脑子里出现了一些问题:测试这种软件是否有“正式”的良好实践?在进行集成测试时,如何在多个连接/高延迟情况下测试此服务器的性能(更具体地说,如何模拟这些情况)?为什么有Socket.Accept / Socket.Receive的异步版本?我可以替换异步方法来在单独的线程中处理它们的同步版本吗?

3 个答案:

答案 0 :(得分:1)

我不熟悉套接字对象。但是,我做了一些关于测试的研究。看起来你走在正确的轨道上。编写可以引用将在生产或测试对象中使用的实际对象的接口通常被认为是良好的做法。这种模式称为“依赖注入”。

我不知道套接字是如何工作的,但是你可以为测试目的做的是创建一个新的测试对象来代替你想要测试的套接字。此测试对象可以简单地调用Thread.Sleep(x)以在返回数据之前添加一些模拟延迟。

编辑:我还想指出,您必须非常小心地确定代码中网络延迟的确切位置,以便在注入人工延迟时,您将它添加到代码中将在现实世界中出现的位置。

答案 1 :(得分:1)

您可以通过创建代理服务器来模拟高延迟,以便在重新发送数据时添加延迟。

答案 2 :(得分:0)

  

是否有任何“正式”良好做法   在测试这种软件?

我可以对此发言,但我确信这里有一些很好的信息,不论是在堆栈还是野外。

  

进行集成测试时,如何进行   我测试这个的性能   服务器在多个连接/高   延迟情况(更具体地说,   如何模拟这些情况)?

对于一个简单的开始,编写一些测试和日志记录例程,在一个单独的盒子上运行它们,这会给服务器带来一系列请求......包括无意义的请求。在两者上运行log4net也会有所帮助。如前所述,可以通过一种代理来介绍一些滞后...一个位于客户端和服务器之间的盒子。客户端指向代理,代理修改数据...延迟,更改数据包顺序等....发送到服务器...反向并重复。稍微偏离......我会避免Thread.Sleep(...)。最好使用这样的东西:

lock (timelock) { Monitor.Wait(timelock, TimeoutInMilliseconds); }
  

...的异步版本   Socket.Accept / Socket.Receive?我可以吗   替换异步方法   处理他们的同步版本   单独的线程?

您有许多选项,异步方法,普通旧线程,线程池,TPL等。最佳选择是特定于应用程序。

以下是Asynchronous Server Socket Example上的MSDN条目中的sockets

幸运的是...... O'Reilly的书:C# 4.0 in a Nutshell有一套优秀的TCP Server examples,涵盖阻塞/非阻塞表现形式的异步/线程方法。这是其中一个例子......

  public class Server
  {
    public void Serve(IPAddress address, int port)
    {

      TcpListener listener = new TcpListener(address, port);
      listener.Start();
      while (true)
      {
        TcpClient c = listener.AcceptTcpClient();
        Task.Factory.StartNew(Accept, c);
      }
    }

    void Accept(object clientObject)
    {
      using (TcpClient client = (TcpClient)clientObject)
      {
        using (NetworkStream n = client.GetStream())
        {
          byte[] data = new byte[5000];

          int bytesRead = 0; int chunkSize = 1;

          while (bytesRead < data.Length && chunkSize > 0)
          {
            bytesRead +=
              chunkSize = n.Read /// Read is blocking
                (data, bytesRead, data.Length - bytesRead);
          }

          Array.Reverse(data);
          n.Write                /// Write is blocking
            (data, 0, data.Length);
        }
      }
    }
  }

希望这有用。

P.S。获取C# 4.0 in a Nutshell ...好的副本。