• 实现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);
    }
    
    
    
  • 相关阅读:
    改变对象的字符串提示
    perl 和 python中的回调函数
    shiro权限验证标签
    user_tables 的信息依赖于统计信息
    centos jdk 1.7升级到1.8后显示还是1.7
    7.1 可接受任意数量参数的函数:
    IntelliJ IDEA中怎么查看文件中所有方法(类似eclipse里面的outline)
    Intellij IDEA 代码格式化与eclipse保持风格一致
    jquery-1.9.1.min.js:69 Uncaught TypeError: Illegal invocation
    python json模块
  • 原文地址:https://www.cnblogs.com/joeylee97/p/8946824.html
Copyright © 2020-2023  润新知