zoukankan      html  css  js  c++  java
  • 实现TTCP (检测TCP吞吐量)

    实现TTCP (检测TCP吞吐量)

    应用层协议

    为了解决TCP粘包问题以及客户端阻塞问题
    设计的应用层协议如下:

    //告知要发送的数据包个数和长度
    struct SessionMessage
    {
      int32_t number;
      int32_t length;
    } __attribute__ ((__packed__));
    
    //数据包
    struct PayloadMessage
    {
      int32_t length;
      char data[0];//使用char[0]来表示不定长的数据,可以考虑用const char* 和 std::unique_ptr代替
    };
    

    为什么要设计应用层ACK?

    因为我们测量的是应用层的流量,只有这样才能保证测出的流量是有应用层收到的而不是传输层收到的,具体一点说,TCP 的 ACK 表示对方的协议栈已经收到了你发的数据,不代表对方的应用程序收到了你发的消息。

    测试指标

    带宽 Mb/s
    测试程序的性能指标: 传输带宽,QPS/TPS, 以及 CPU利用率,延迟等等。

    程序代码

    我们主要关注业务逻辑,客户端和服务端的主要代码如下

    客户端

    void transmit(const Options& opt)
    {
      InetAddress addr(opt.port);
      if (!InetAddress::resolve(opt.host.c_str(), &addr))
      {
        printf("Unable to resolve %s
    ", opt.host.c_str());
        return;
      }
    
      printf("connecting to %s
    ", addr.toIpPort().c_str());
      TcpStreamPtr stream(TcpStream::connect(addr));
      if (!stream)
      {
        printf("Unable to connect %s
    ", addr.toIpPort().c_str());
        perror("");
        return;
      }
    
      if (opt.nodelay)
      {
        stream->setTcpNoDelay(true);
      }
      printf("connected
    ");
      double start = now();
      struct SessionMessage sessionMessage = { 0, 0 };
      sessionMessage.number = htonl(opt.number);
      sessionMessage.length = htonl(opt.length);
      if (stream->sendAll(&sessionMessage, sizeof(sessionMessage)) != sizeof(sessionMessage))
      {
        perror("write SessionMessage");
        return;
      }
    
      const int total_len = sizeof(int32_t) + opt.length;
      PayloadMessage* payload = static_cast<PayloadMessage*>(::malloc(total_len));
      std::unique_ptr<PayloadMessage, void (*)(void*)> freeIt(payload, ::free);
      assert(payload);
      payload->length = htonl(opt.length);
      for (int i = 0; i < opt.length; ++i)
      {
        payload->data[i] = "0123456789ABCDEF"[i % 16];
      }
    
      double total_mb = 1.0 * opt.length * opt.number / 1024 / 1024;
      printf("%.3f MiB in total
    ", total_mb);
    
      for (int i = 0; i < opt.number; ++i)
      {
        int nw = stream->sendAll(payload, total_len);
        assert(nw == total_len);
    
        int ack = 0;
        int nr = stream->receiveAll(&ack, sizeof(ack));
        assert(nr == sizeof(ack));
        ack = ntohl(ack);
        assert(ack == opt.length);
      }
    
      double elapsed = now() - start;
      printf("%.3f seconds
    %.3f MiB/s
    ", elapsed, total_mb / elapsed);
    }
    

    服务端

    void receive(const Options& opt)
    {
      Acceptor acceptor(InetAddress(opt.port));
      TcpStreamPtr stream(acceptor.accept());
      if (!stream)
      {
        return;
      }
      struct SessionMessage sessionMessage = { 0, 0 };
      if (stream->receiveAll(&sessionMessage, sizeof(sessionMessage)) != sizeof(sessionMessage))
      {
        perror("read SessionMessage");
        return;
      }
    
      sessionMessage.number = ntohl(sessionMessage.number);
      sessionMessage.length = ntohl(sessionMessage.length);
      printf("receive buffer length = %d
    receive number of buffers = %d
    ",
             sessionMessage.length, sessionMessage.number);
      double total_mb = 1.0 * sessionMessage.number * sessionMessage.length / 1024 / 1024;
      printf("%.3f MiB in total
    ", total_mb);
    
      const int total_len = sizeof(int32_t) + sessionMessage.length;
      PayloadMessage* payload = static_cast<PayloadMessage*>(::malloc(total_len));
      std::unique_ptr<PayloadMessage, void (*)(void*)> freeIt(payload, ::free);
      assert(payload);
    
      double start = now();
      for (int i = 0; i < sessionMessage.number; ++i)
      {
        payload->length = 0;
        if (stream->receiveAll(&payload->length, sizeof(payload->length)) != sizeof(payload->length))
        {
          perror("read length");
          return;
        }
        payload->length = ntohl(payload->length);
        assert(payload->length == sessionMessage.length);
        if (stream->receiveAll(payload->data, payload->length) != payload->length)
        {
          perror("read payload data");
          return;
        }
        int32_t ack = htonl(payload->length);
        if (stream->sendAll(&ack, sizeof(ack)) != sizeof(ack))
        {
          perror("write ack");
          return;
        }
      }
      double elapsed = now() - start;
      printf("%.3f seconds
    %.3f MiB/s
    ", elapsed, total_mb / elapsed);
    }
    
    
    
  • 相关阅读:
    快排
    装载问题加强版
    從 Internet 安裝 Cygwin
    操作系统:基于页面置换算法的缓存原理详解(上)
    Java设计模式——适配器模式
    Unity 协程使用指南
    2015年总结
    基于正态分布的图片高斯模糊算法
    数据结构:关于AVL树的平衡旋转详解
    算法:关于生成抽样随机数的这些算法
  • 原文地址:https://www.cnblogs.com/joeylee97/p/8946824.html
Copyright © 2011-2022 走看看