【问题标题】:How do I properly simulate high latency on a C# socket server test?如何正确模拟 C# 套接字服务器测试的高延迟?
【发布时间】:2010-07-09 13:29:19
【问题描述】:

我有一个直接使用“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 的异步版本?我可以替换异步方法以在单独的线程中处理它们的同步版本吗?

【问题讨论】:

    标签: c# .net testing sockets


    【解决方案1】:

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

    【讨论】:

    • 您的意思是模拟代理服务器?你能举个例子吗?
    【解决方案2】:

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

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

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

    【讨论】:

    • 你的意思是将一些二进制数据分成块并使用 Thread.Sleep 间隔发送每个块吗?这是一个可能的解决方案,但我不确定这是否正确模拟了高延迟,不过我可能会尝试一下。处理多个并发连接怎么样?怎么处理?
    • 我的意思是,既然您已经编写了自己的接口,那么您应该能够编写一个模拟延迟的测试对象并在您的测试环境中使用它。我不能说应该如何模拟延迟的细节。
    【解决方案3】:

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

    我可以谈谈这个,但我确信这里有一些很好的信息在堆栈上或在野外。

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

    作为一个简单的开始,编写一些测试和日志记录例程,在一个单独的盒子上运行它们,这会用真实的请求敲击服务器......包括无意义的请求。在两者上运行 log4net 也会有所帮助。正如已经提到的,可以通过某种代理来引入一些延迟……一个位于客户端和服务器之间的盒子。客户端指向代理,代理修改数据...延迟,更改数据包顺序等...发送到服务器...反向并重复。顺便说一句...我会避免使用 Thread.Sleep(...)。最好使用这样的东西:

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

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

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

    这是来自 sockets 上的 MSDN 条目的 Asynchronous Server Socket Example

    幸运的是……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);
            }
          }
        }
      }
    

    希望这有帮助。

    附言获取一份C# 4.0 in a Nutshell...很好。

    【讨论】:

    • 感谢您的提示,我去看看这本书。我认为设置另一台机器只是为了做一些集成测试有点矫枉过正。我希望测试快速并通过按一个按钮运行它们
    • 您当然可以从同一个盒子进行测试..但是..您将共享同一个网络堆栈。所以你的结果会有点偏差。这不是一个交易破坏者,你应该知道可能的副作用......享受吧。
    猜你喜欢
    • 1970-01-01
    • 2021-10-15
    • 2021-03-21
    • 1970-01-01
    • 2013-03-19
    • 2021-06-17
    • 2019-10-09
    • 2015-12-15
    • 1970-01-01
    相关资源
    最近更新 更多