源码可以从陈硕的github上下载到,位置在muduo-master\examples\ace\ttcp

TTCP是一个传统的测试TCP性能的工具,它主要测试两个机器之间TCP的吞吐量,在应用层模拟消息传递的过程——客户端发送一个包,服务端对包进行确认,并且在确认之前客户端不发送下一个包。可以设置发包的数量和每个包的大小,程序计算传输所有包所用的时间,然后计算出带宽。

操作流程图

以上发送的message都是在应用层中体现的。当一个client发起ttcp的请求时,首先会向server发送一个SessionMessage,里边主要包含了即将发送的数据包个数和每个包的长度。PayloadMessage便是实际的数据,里边包含了一个表示长度的length,和实际的数据data,其中data使用了柔性数组。

main.cc

#include <examples/ace/ttcp/common.h>#include <assert.h>int main(int argc, char* argv[])
{Options options;                               //用来保存输入的参数信息if (parseCommandLine(argc, argv, &options))    //把命令行输入的参数保存到结构体中{if (options.transmit)                        //让发送端和接收端分别执行对应的函数{transmit(options);}else if (options.receive){receive(options);}else{assert(0);}}
}

common.h

#pragma once#include <string>
#include <stdint.h>struct Options
{uint16_t port;                 //端口int length;                     //报文长度int number;                       //报文数量bool transmit, receive, nodelay;  //发送端,接收端,是否在传输层禁用negla算法std::string host;                    //主机名Options(): port(0), length(0), number(0),transmit(false), receive(false), nodelay(false){}
};bool parseCommandLine(int argc, char* argv[], Options* opt);      //解析命令
struct sockaddr_in resolveOrDie(const char* host, uint16_t port);   //通过域名和端口解析出服务端的sockaddrstruct SessionMessage               //本次请求的信息
{int32_t number;                    //报文数量int32_t length;                   //报文长度
} __attribute__ ((__packed__));struct PayloadMessage                //消息报文
{int32_t length;                    //长度char data[0];                       //数据
};void transmit(const Options& opt);    //发送端void receive(const Options& opt);  //接收端

ttcp_blocking.cc

#include <examples/ace/ttcp/common.h>
#include <muduo/base/Timestamp.h>
#include <muduo/base/Types.h>#undef NDEBUG#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>#include <netinet/in.h>
#include <arpa/inet.h>static int acceptOrDie(uint16_t port)                                   //一次只服务一个客户端,创建一个listenfd收到连接就close,返回clientsock
{int listenfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);assert(listenfd >= 0);int yes = 1;if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))){perror("setsockopt");exit(1);}struct sockaddr_in addr;muduo::memZero(&addr, sizeof(addr));addr.sin_family = AF_INET;addr.sin_port = htons(port);addr.sin_addr.s_addr = INADDR_ANY;if (bind(listenfd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr))){perror("bind");exit(1);}if (listen(listenfd, 5)){perror("listen");exit(1);}struct sockaddr_in peer_addr;muduo::memZero(&peer_addr, sizeof(peer_addr));socklen_t addrlen = 0;int sockfd = ::accept(listenfd, reinterpret_cast<struct sockaddr*>(&peer_addr), &addrlen);if (sockfd < 0){perror("accept");exit(1);}::close(listenfd);return sockfd;
}static int write_n(int sockfd, const void* buf, int length)            //写length个字符,返回写成功的字符个数
{int written = 0;while (written < length){ssize_t nw = ::write(sockfd, static_cast<const char*>(buf) + written, length - written);if (nw > 0){written += static_cast<int>(nw);}else if (nw == 0){break;  // EOF}else if (errno != EINTR){perror("write");break;}}return written;
}static int read_n(int sockfd, void* buf, int length)               //读legnth个字符,返回读到的字符个数
{int nread = 0;while (nread < length){ssize_t nr = ::read(sockfd, static_cast<char*>(buf) + nread, length - nread);if (nr > 0){nread += static_cast<int>(nr);}else if (nr == 0){break;  // EOF}else if (errno != EINTR){perror("read");break;}}return nread;
}void transmit(const Options& opt)                                                      //发送端执行
{struct sockaddr_in addr = resolveOrDie(opt.host.c_str(), opt.port);                   //输入域名端口,返回表示server的sockaddrprintf("connecting to %s:%d\n", inet_ntoa(addr.sin_addr), opt.port);int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);assert(sockfd >= 0);int ret = ::connect(sockfd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)); //连接服务端if (ret){perror("connect");printf("Unable to connect %s\n", opt.host.c_str());::close(sockfd);return;}printf("connected\n");muduo::Timestamp start(muduo::Timestamp::now());                                       //记录当前时间struct SessionMessage sessionMessage = { 0, 0 };                                       //填写信息报文sessionMessage.number = htonl(opt.number);sessionMessage.length = htonl(opt.length);if (write_n(sockfd, &sessionMessage, sizeof(sessionMessage)) != sizeof(sessionMessage))//如果没有全部发送直接退出{perror("write SessionMessage");exit(1);}const int total_len = static_cast<int>(sizeof(int32_t) + opt.length);                    //计算数据报文长度PayloadMessage* payload = static_cast<PayloadMessage*>(::malloc(total_len));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\n", total_mb);for (int i = 0; i < opt.number; ++i)                                                  //发收数据{int nw = write_n(sockfd, payload, total_len);assert(nw == total_len);int ack = 0;int nr = read_n(sockfd, &ack, sizeof(ack));                                            //每个包发出之后要等收到对应的确认再发下一个assert(nr == sizeof(ack));ack = ntohl(ack);assert(ack == opt.length);}::free(payload);::close(sockfd);double elapsed = timeDifference(muduo::Timestamp::now(), start);                     //输出结果printf("%.3f seconds\n%.3f MiB/s\n", elapsed, total_mb / elapsed);
}void receive(const Options& opt)
{int sockfd = acceptOrDie(opt.port);                                                   //接受客户端连接struct SessionMessage sessionMessage = { 0, 0 };if (read_n(sockfd, &sessionMessage, sizeof(sessionMessage)) != sizeof(sessionMessage))//读消息报文{perror("read SessionMessage");exit(1);}sessionMessage.number = ntohl(sessionMessage.number);sessionMessage.length = ntohl(sessionMessage.length);printf("receive number = %d\nreceive length = %d\n",sessionMessage.number, sessionMessage.length);const int total_len = static_cast<int>(sizeof(int32_t) + sessionMessage.length);PayloadMessage* payload = static_cast<PayloadMessage*>(::malloc(total_len));         //申请对应大小的缓冲区assert(payload);for (int i = 0; i < sessionMessage.number; ++i)                                       //读数据发ack{payload->length = 0;if (read_n(sockfd, &payload->length, sizeof(payload->length)) != sizeof(payload->length)){perror("read length");exit(1);}payload->length = ntohl(payload->length);assert(payload->length == sessionMessage.length);if (read_n(sockfd, payload->data, payload->length) != payload->length){perror("read payload data");exit(1);}int32_t ack = htonl(payload->length);if (write_n(sockfd, &ack, sizeof(ack)) != sizeof(ack)){perror("write ack");exit(1);}}::free(payload);::close(sockfd);
}

简单的TCP带宽测试工具TTCP相关推荐

  1. 4测试命令_局域网带宽测试工具-iPerf3

    工具名称:iPerf3 官网: https://iperf.fr/ 简介:用于TCP,UDP和SCTP的终极速度测试工具: 功能:跨平台(Windows,Linux,Android,MacOS X,F ...

  2. 带宽测试工具 iperf3

    带宽测试工具-iperf3 iperf3是一款带宽测试工具,它支持调节各种参数,比如通信协议,数据包个数,发送持续时间,测试完会报告网络带宽,丢包率和其他参数. 安装 操作系统:centos7.0 软 ...

  3. 默蓝网络通信TCP/HTTP测试工具介绍

    默蓝网络通信TCP/HTTP测试工具介绍 默蓝网络通信TCP/HTTP测试工具为广大技术开发人员提供的通信测试工具,其具备如下功能: 1.支持TCP/IP协议的网络通信,TCP服务端和客户端,可单条发 ...

  4. tcp连接测试工具_“国货之光”!国产弱网测试神器 QNET,比主流弱网测试工具强在哪?...

    弱网测试,是软件测试不可缺少的一个环节,但目前主流的一些弱网测试工具,或多或少暴露了一些缺点,这工具称不称手只有自己知道. 最近腾讯出了一款弱网测试神器 QNET,被誉为测试行业的"国货之光 ...

  5. 分布式TCP压力测试工具 tcpcopy

    tcpcopy是一种应用请求复制(基于tcp的packets)工具,其应用领域较广,我们曾经应用于网易的广告投放系统,urs系统,nginx hmux协议开发等系统,避免了上线带来的很多问题. 总体说 ...

  6. bandwidth 0.32k 发布,内存带宽测试工具

    bandwidth 0.32k 修复了一些小的 AVX 问题. Bandwidth 是一个内存带宽测试的基准工具,但它也可以测量网络带宽.它可以测量每个内存系统的最大内存带宽,包括主内存,L1和L2缓 ...

  7. 手把手写C++服务器(11):手撕网络带宽测试工具TTCP

    本系列文章导航: 手把手写C++服务器(0):专栏文章-汇总导航[更新中] 前言:TTCP诞生于1984年,是Unix很流行的网络带宽测试工具,并从中衍生出了著名的网络测试工具Ipref.TTCP手撕 ...

  8. 【开发工具】【stream】内存带宽测试工具(Stream)的使用

    获取更多相关的嵌入式开发工具,可收藏系列博文,持续更新中: [开发工具]嵌入式常用开发工具汇总帖 Stream简介 STREAM是一套综合性能测试程序集,通过fortran和C两种高级且高效的语言编写 ...

  9. linux 服务器带宽测试工具

    很多时候我们需要测试Linux服务器的上行和下行宽带.在可用于测试宽带速度的网站中,Speedtest.net也许是使用最广泛的应用"之一". Speedtest.net提供了一个 ...

最新文章

  1. 行人检测--What Can Help Pedestrian Detection?
  2. 【OSX】OSX下采用MAMP的PHP替换系统自带PHP
  3. php route取值,route命令详解
  4. python报错处理_python mysql 断连报错处理
  5. qtextedit 默认文案_QT中常用的控件说明.md
  6. 需要天天读月月读年年读的书
  7. 思科(Cisco)路由器策略路由配置详解
  8. 中科院发布规范学术论著署名问题负面行为清单
  9. thin还是thick(续),实证新结论!
  10. http请求被挂起 cancled 原因
  11. Mac如何简单的翻录3D蓝光视频
  12. .net反混淆脱壳工具de4dot的使用
  13. YOLO3算法个人算法理解心得
  14. PDF转CAD工具怎么选择
  15. 大数据技术及大数据架构
  16. Java中Math类的随机数公式
  17. 电影拍摄胶片比例_用于创建自己的电影胶片的10个很酷的Photoshop教程
  18. Servlet本身的init,service,destory生命周期方法
  19. 替代触发器和系统触发器
  20. 【RDMA】RDMA网卡通讯

热门文章

  1. QML类型——ListView
  2. 剑桥大学 计算机课程,剑桥大学计算机课程
  3. EXCEL常用函数substitute的用法
  4. 联邦学习(Federated Learning)概述
  5. Federated Continual Learning with Weighted Inter-client Transfer——论文笔记
  6. css解决uniapp使用image标签图片无法撑满全屏问题
  7. 如何做好短视频营销?短视频推广怎么做
  8. 大厂偏爱的Agent技术究竟是个啥
  9. Java 使用 Easyexcel 实现 excel 导出,附前端下载方法
  10. 计算机ppt社团教案,计算机社团教案