tcprstat是percona用来监测mysql响应时间的。不过对于任何运行在TCP协议上的响应时间,都可以用。
tcprstat和tcpdump一样,使用libpcap库进行抓包,然后再通过程序对抓取的tcp包进行分析。
1、通过分析来源ip和目标ip,看那个ip是本地ip,来判断是进来的包(请求包)还是出去的包(响应包)。
2、如果包的数据大小为0,那么就跳过,不再处理。数据大小为0的视为tcp控制包。
3、如果数据包为进来的包(请求包),则插入一条记录到哈希表。
4、如果数据包为出去的包(响应包),则用现在的包和之前插入哈希表中的响应包做时间差计算。并把之前的包在哈希表中删除。
数据包分析的代码在process-packet.c文件中,方法如下:
int process_ip(pcap_t *dev, const struct ip *ip, struct timeval tv) { char src[16], dst[16], *addr; int incoming; unsigned len; addr = inet_ntoa(ip->ip_src); strncpy(src, addr, 15); src[15] = ' '; addr = inet_ntoa(ip->ip_dst); strncpy(dst, addr, 15); dst[15] = ' '; if (is_local_address(ip->ip_src)) incoming = 0; else if (is_local_address(ip->ip_dst)) incoming = 1; else return 1; len = htons(ip->ip_len); switch (ip->ip_p) { struct tcphdr *tcp; uint16_t sport, dport, lport, rport; unsigned datalen; case IPPROTO_TCP: tcp = (struct tcphdr *) ((unsigned char *) ip + sizeof(struct ip)); #if defined(__FAVOR_BSD) sport = ntohs(tcp->th_sport); dport = ntohs(tcp->th_dport); datalen = len - sizeof(struct ip) - tcp->th_off * 4; // 4 bits offset #else sport = ntohs(tcp->source); dport = ntohs(tcp->dest); datalen = len - sizeof(struct ip) - tcp->doff * 4; #endif // Capture only "data" packets, ignore TCP control if (datalen == 0) break; if (incoming) { lport = dport; rport = sport; inbound(tv, ip->ip_dst, ip->ip_src, lport, rport); } else { lport = sport; rport = dport; outbound(tv, ip->ip_src, ip->ip_dst, lport, rport); } break; default: break; } return 0; }
ps:在这个文件中,process_packet 方法用户获取头信息。