实现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\n", opt.host.c_str());
return;
}
printf("connecting to %s\n", addr.toIpPort().c_str());
TcpStreamPtr stream(TcpStream::connect(addr));
if (!stream)
{
printf("Unable to connect %s\n", addr.toIpPort().c_str());
perror("");
return;
}
if (opt.nodelay)
{
stream->setTcpNoDelay(true);
}
printf("connected\n");
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\n", 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\n%.3f MiB/s\n", 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\nreceive number of buffers = %d\n",
sessionMessage.length, sessionMessage.number);
double total_mb = 1.0 * sessionMessage.number * sessionMessage.length / 1024 / 1024;
printf("%.3f MiB in total\n", 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\n%.3f MiB/s\n", elapsed, total_mb / elapsed);
}
实现TTCP (检测TCP吞吐量)的更多相关文章
- 怎样检测TCP/UDP端口的连通性
1 TCP端口的连通性 TC端口的连通性,一般通过telnet检测: TCP协议是面向连接的,可以直接通过telnet命令连接 telnet host-ip port 2 UDP端口的连通性 因为公司 ...
- TCP连接异常断开检测(转)
TCP是一种面向连接的协议,连接的建立和断开需要通过收发相应的分节来实现.某些时候,由于网络的故障或是一方主机的突然崩溃而另一方无法检测到,以致始终保持着不存在的连接.下面介绍一种方法来检测这种异常断 ...
- (转)TCP连接异常断开检测
TCP是一种面向连接的协议,连接的建立和断开需要通过收发相应的分节来实现.某些时候,由于网络的故障或是一方主机的突然崩溃而另一方无法检测到,以致始终保持着不存在的连接.下面介绍一种方法来检测这种异常断 ...
- TCP系列37—Keep Alive—1、TCP存活检测
一.TCP存活(keepalive)检测的背景 对于TCP设计来说,如果一个客户端和服务器端建立连接后,不在进行数据传输,那么这个连接将会一直存在下去,理论上即使中间的路由器崩溃重启.或者中间的网络线 ...
- 心跳机制tcp keepalive的讨论、应用及“断网”、"断电"检测的C代码实现(Windows环境下)
版权声明:本文为博主原创文章,转载时请务必注明本文地址, 禁止用于任何商业用途, 否则会用法律维权. https://blog.csdn.net/stpeace/article/details/441 ...
- High Performance Browser Networking - TCP UDP TLS
延迟 定义和标准延迟 延迟简单地说,它是一种转移或信息包从起点到终点,所花费的时间. 延迟=发送延迟+传播延迟+处理延迟+排队延迟: Propagation delay 传播时延 传播时延这个概念.是 ...
- TCP协议原理与格式初探
目录 可靠数据传输原理 停等传输下的情况 1.经过完全可靠信道的可靠数据传输 2.经具有比特差错信道的可靠数据传输 3.经具有比特差错的丢包信道的可靠数据传输 流水线传输 1.回退N步(Go-Back ...
- TCP拥塞控制详解
1. 拥塞原因与代价 拥塞的代价 当分组的到达速率接近链路容量时,分组经历巨大的排队时延. 发送方必须执行重传以补偿因为缓存溢出而丢弃的分组. 发送方在遇到大时延时进行的不必要重传会引起路由器利用其链 ...
- 通过PowerShell获取TCP响应(类Telnet)
通常情况下,为了检测指定的TCP端口是否存活,我们都是通过telnet指定的端口看是否有响应来确定,然而默认情况下win8以后的系统默认是不安装telnet的.设想一下如果你黑进了一个服务器,上面没装 ...
随机推荐
- 【求助】NdisSend,自定义数据包发送失败?
做ndis hook的时候,自定义了一个数据包,包结构应该没有问题,填充NDIS_PACKET结构是这样的,先初始化: NdisAllocatePacketPool(&nStat ...
- centos7 samba配置完成后不管怎么登陆都会显示密码错误的解决方案
添加系统用户 useradd samba 添加samba用户 smbpasswd -a samba 激活samba用户 smbpasswd -e samba 1.win+r运行secpol.msc打开 ...
- vue表单验证:vee-validate中文提示
官方文档:https://baianat.github.io/vee-validate/guide/ vee-validate可用于vue项目中进行表单验证,使用方法在官方API上都可以查到: 使用过 ...
- CentOS 7 编译 mysql 8.0.12
步骤一:安装mysql依赖 yum install -y libaio numactl 步骤二:下载mysql社区版 wget https://dev.mysql.com/get/Downloads/ ...
- 蓝牙学习 (7) - raspberrryPi 扫描TI sensorTag
前面几篇分别简单涉及了 raspberryPi上bluez BLE sniffer TI SensorTag https://blog.csdn.net/feiwatson/article/detai ...
- 如何用纯 CSS 绘制一个充满动感的 Vue logo
效果预览 在线演示 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/zaqKPx 可交互视频教 ...
- windows python MySQLdb 安装配置
一.环境 系统:windows10/7/8 软件: 1.python2.7.XX(https://www.python.org/downloads/或者https://www.python.org/f ...
- 关于$test$plusargs和$value$plusargs的小结
见: http://www.cnblogs.com/nanoty/p/4355245.html
- dbfread报错ValueError错误解决方法
问题 我在用dbfread处理.dbf数据的时候出现了报错 ValueError("could not convert string to float: b'.'",) 然后查找. ...
- [转]automaticallyAdjustsScrollViewInsets(个人认为iOS7中略坑爹的属性)
@当我们在一个UIViewController中同时创建2个tableView的时候,如果把它们的frame中的Y坐标设置为一样,你可能会发现它们的位置并没有达到你想要的结果.比如第一tableVie ...