tcpreplay 缓存算法研究
一. 缓存算法
1.1 算法目的
流量拆分算法的运算会明显影响包的发送速率,为了提高发送速率, tcpreplay 使用了缓存机制,该部分代码也封装在tcpprep工具里,运行 tcpprep (tcp-preparation)工具,结果是一个针对性的缓存文件,该文件存放流量拆分算法的运算结果。同时,cache.c 存放了部分读取cachefile的函数。
1.2 算法思想
如何设计符合目的的缓存?达到即高效又节省?
最简单就是使用bool[SIZE] ,存放 0和1,这样的数据结构使用1个字节存放标识,可以表示2个方向的流量。但是用1个字节表示一个packet完全没必要,可以用1个bit表示一个packet。用如下方法可以做到:
使用一个比特位表示一个packet 的方法
包的id: packetid
Index = packetid/8
Bit = packetid%8
Byte = &Cache[Index]
写缓存: *Byte = *Byte + (1<<Bit)
读缓存: result = Cache[Index] & (char)(1 << Bit)
上述方法依然不完善,第一,pcap 包包含的 packets 的数量是未知的,用固定的 char 数组存放不够灵活。其二,如果缓存结果需要扩展,比如在‘客户端->服务端’‘服务端->客户端’两种packets状态之外,还有‘发送’‘不发送’(表示该packet发送与否),‘正确’‘错误’(表示该packet是否异常)等状态运算结果,上述算法无法扩展。
解决第一个问题,是使用数组链表的方式取代单一数组的方式。每个链表节点存放一个可配的小数组,当当前节点数组空间不够的时候,再生成一个小数组,连在链表后面。这样的缓存,可以根据具体的packets 数灵活得分配空间。
解决第二个问题,是设定一个参数 packets_per_byte ,表示一个字节可以容纳多少packets缓存信息,只有2种状态时该参数值为 8 ,表示4种状态时该参数值为 4。6 种状态值是2,以此类推。packets_per_byte = 1 时,1 个字节可以最多表示 16 种缓存状态。
Tcpprep3.4.4使用2个bit表示一个packet,下面是这种情况下算法思想的图形表示:
1.1 算法流程
使用缓存以及不使用缓存两种情况下的发包流程。
1.1 算法实现
1.1.1 数据结构
struct tcpr_cache_s { /*一个缓存节点的数据结构*/
char data[CACHEDATASIZE]; /*该节点的小数组*/
unsigned int packets; /*该节点已经存放缓存结果的packet的数目*/
struct tcpr_cache_s *next; /*链表指针*/
};
typedef struct tcpr_cache_s tcpr_cache_t;
struct tcpr_cache_file_hdr_s {/*缓存文件头数据结构*/
char magic[8]; /*文件标识*/
char version[4]; /*缓存版本*/
u_int64_t num_packets; /* total # of packets in file */
u_int16_t packets_per_byte; /*每个字节存放多少个packet的缓存数据*/
u_int16_t comment_len; /* how long is the user comment? */
} __attribute__((__packed__));
enum tcpr_dir_e { /*缓存运算结果种类*/
TCPR_DIR_ERROR = -1,/*异常packet,该状态没有加入缓存,而是作为返回值*/
TCPR_DIR_NOSEND = 0, /*是否发送*/
TCPR_DIR_C2S = 1, /* 客户端->服务器,从 PRIMARY 接口回放*/
TCPR_DIR_S2C = 2 /* 服务器->客户端,从SECONDARY接口回放 */
};
typedef enum tcpr_dir_e tcpr_dir_t;
1.1.2 主要函数实现
/**
*生成1个packet的缓存数据
*/
tcpr_dir_t
add_cache(tcpr_cache_t ** cachedata, const int send, const tcpr_dir_t interface)
{
static tcpr_cache_t *lastcache = NULL;
u_char *byte = NULL;
u_int32_t bit;
tcpr_dir_t result = TCPR_DIR_ERROR;
COUNTER index;
if (*cachedata == NULL) { /* 第一次运行,生成第一个节点 */
*cachedata = new_cache();
lastcache = *cachedata;
}
else {
if ((lastcache->packets + 1) > (CACHEDATASIZE *CACHE_PACKETS_PER_BYTE)) { /* 当前节点如果满了,生成一个新节点*/
lastcache->next = new_cache();
lastcache = lastcache->next;
}
}
lastcache->packets++;
if (send == SEND) { /* 是否发送的标志位赋值*/
index = (lastcache->packets - 1) / (COUNTER)CACHE_PACKETS_PER_BYTE;
bit = (((lastcache->packets - 1) % (COUNTER)CACHE_PACKETS_PER_BYTE) *
(COUNTER)CACHE_BITS_PER_PACKET) + 1;
byte = (u_char *) & lastcache->data[index];
*byte += (u_char) (1 << bit);
/* if true, set low order bit. else, do squat */
if (interface == TCPR_DIR_C2S) {/*流量方向的标志位赋值*/
*byte += (u_char)(1 << (bit - 1));
result = TCPR_DIR_C2S;
}
else { result = TCPR_DIR_S2C; }
}
else { result = TCPR_DIR_NOSEND; /*异常情况,结果返回异常*/ }
return result;
}
/**
* 下面函数显示如何根据packet id 读取缓存结果
*/
tcpr_dir_t
check_cache(char *cachedata, COUNTER packetid)
{
COUNTER index = 0;
u_int32_t bit;
if (packetid == 0) err(-1, "packetid must be > 0");
/* 定位到缓存数组的具体位 */
index = (packetid - 1) / (COUNTER)CACHE_PACKETS_PER_BYTE;
bit = (u_int32_t)(((packetid - 1) % (COUNTER)CACHE_PACKETS_PER_BYTE) *(COUNTER)CACHE_BITS_PER_PACKET) + 1;
if (!(cachedata[index] & (char)(1 << bit))) {
return TCPR_DIR_NOSEND; /*返回是否发送的标志位结果*/
}
/* go back a bit to get the interface */
bit--;
if (cachedata[index] & (char)(1 << bit)) { return TCPR_DIR_C2S; }
else { return TCPR_DIR_S2C; } /*返回流量方向结果*/
return TCPR_DIR_ERROR; /*如果上述情况都没发送,返回异常*/
}
1.2 实验结果
1.2.1 实验1
拥有14个packet的pcap生成的缓存文件
tcpreplay 缓存算法研究的更多相关文章
- tcpreplay 流量拆分算法研究
1.1 算法目的 现在网络架构一般是Client-Server架构,所以网络流量一般是分 C-S 和 S-C 两个方向.tcpdump等抓包工具获取的pcap包,两个流向的数据没有被区分.流量方向的 ...
- Akamai在内容分发网络中的算法研究(翻译总结)
作者 | 钱坤 钱坤,腾讯后台开发工程师,从事领域为流媒体CDN相关,参与腾讯TVideo平台开发维护. 原文是<Algorithmic Nuggets in Content Delivery& ...
- 静态频繁子图挖掘算法用于动态网络——gSpan算法研究
摘要 随着信息技术的不断发展,人类可以很容易地收集和储存大量的数据,然而,如何在海量的数据中提取对用户有用的信息逐渐地成为巨大挑战.为了应对这种挑战,数据挖掘技术应运而生,成为了最近一段时期数据科学的 ...
- 算法进阶面试题06——实现LFU缓存算法、计算带括号的公式、介绍和实现跳表结构
接着第四课的内容,主要讲LFU.表达式计算和跳表 第一题 上一题实现了LRU缓存算法,LFU也是一个著名的缓存算法 自行了解之后实现LFU中的set 和 get 要求:两个方法的时间复杂度都为O(1) ...
- Working Set缓存算法(转)
为了加深对缓存算法的理解,特转此篇,又由于本文内容过多,故不做翻译,原文地址Working Set页面置换算法 In the purest form of paging, processes are ...
- Android ImageCache图片缓存,使用简单,支持预取,支持多种缓存算法,支持不同网络类型,扩展性强
本文主要介绍一个支持图片自动预取.支持多种缓存算法的图片缓存的使用及功能.图片较大需要SD卡保存情况推荐使用ImageSDCardCache. 与Android LruCache相比主要特性:(1). ...
- 缓存算法之belady现象
前言 在使用FIFO算法作为缺页置换算法时,分配的缺页增多,但缺页率反而提高,这样的异常现象称为belady Anomaly. 虽然这种现象说明的场景是缺页置换,但在运用FIFO算法作为缓存算法时,同 ...
- android上的缓存、缓存算法和缓存框架
1.使用缓存的目的 缓存是存取数据的临时地,因为取原始数据代价太大了,加了缓存,可以取得快些.缓存可以认为是原始数据的子集,它是从原始数据里复制出来的,并且为了能被取回,被加上了标志. 在andr ...
- java缓存算法【转】
http://my.oschina.net/u/866190/blog/188712 提到缓存,不得不提就是缓存算法(淘汰算法),常见算法有LRU.LFU和FIFO等算法,每种算法各有各的优势和缺点及 ...
随机推荐
- [Codeforces958F2]Lightsabers (medium)(思维)
Description 题目链接 Solution 设一个l指针指向当前数列左边,从左往右扫描一遍,将当前颜色记录, 当所有颜色都得到后,进行判断,如果当前l指向的颜色大于需要的颜色,l后移一位,然后 ...
- Linux之rsync同步工具介绍+inotify同步
1.rsync介绍 Rsync是一款开源的.快速的.多功能的.可实现全量及增量的本地或远程数据同步备份的优秀工具.Rsync软件适用于unix/linux/windows等多种操作平台. rsync, ...
- python Re库的介绍
re库的贪婪匹配和最小匹配 后面跟着?变为最小匹配
- zeppelin的安装与使用
想起马上就能回家了,心情是按捺不住的激动,唉,还是继续努力吧,其实不希望那么快就回家,感觉回去了就意味着马上就要回来了,人真的是神奇呀 今天我们来使用zeppelin,这个就是可以把我们查找的数据可以 ...
- 20145202 《Java程序设计》实验四实验报告
实验名称 Andoid开发基础 实验内容 1.基于Android Studio开发简单的Android应用并部署测试; 2.了解Android组件.布局管理器的使用: 3.掌握Android中事件处理 ...
- 2,版本控制git --分支
有人把 Git 的分支模型称为它的`‘必杀技特性’',也正因为这一特性,使得 Git 从众多版本控制系统中脱颖而出. 为何 Git 的分支模型如此出众呢? Git 处理分支的方式可谓是难以置信的轻量, ...
- Python的类(一)
类(Class): 用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法.对象是类的实例. 类变量:类变量在整个实例化的对象中是公用的.类变量定义在类中且在函数体之外. ...
- 《Cracking the Coding Interview》——第17章:普通题——题目2
2014-04-28 22:05 题目:写个程序判断三连棋哪一方赢了. 解法:三个相同的棋子连成一条横线,竖线或者对角线就判断为赢了. 代码: // 17.2 Write an algorithm t ...
- Python3中文教程
搜索 此文档来源自网络 安装 PYTHON❝ Tempora mutantur nos et mutamur in illis. (时光流转,吾等亦随之而变.) ❞ — 古罗马谚语 深入欢迎来到 Py ...
- QBASIC教程
Qbasic 程序设计入门 BASIC(Beginner’s All-purpose Symbolic Instruction Code 的缩写,意为初学者通用符号指令代码)语言是在1964年由美国的 ...