C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C/C++网络流量分析

Linux C/C++实现网络流量分析工具

作者:程序猿编码

网络流量分析的原理基于对数据包的捕获、解析和统计分析,通过对网络流量的细致观察和分析,帮助管理员了解和优化网络的性能,本文将通过C++实现网络流量分析工具,有需要的可以参考下

网络流量分析的原理基于对数据包的捕获、解析和统计分析,通过对网络流量的细致观察和分析,帮助管理员了解和优化网络的性能、提高网络安全性,并快速排查和解决网络故障和问题。

Linux中的网络流量常见类型

在Linux中,网络流量可以分为几种不同的类型。以下是一些常见的网络流量类型:

TCP流量:TCP(传输控制协议)是一种可靠的、面向连接的协议。TCP流量通常用于传输可靠的数据,例如网页浏览、文件传输等。

UDP流量:UDP(用户数据报协议)是一种无连接的协议,不保证数据的可靠性和顺序。UDP流量通常用于实时应用,如VoIP(网络电话)、视频流传输等。

ICMP流量:ICMP(Internet控制消息协议)用于传输网络控制消息和错误报告。ICMP流量通常用于网络故障排查、Ping命令等。

HTTP流量:HTTP(超文本传输协议)是一种应用层协议,用于在Web浏览器和服务器之间传输数据。HTTP流量通常用于网页浏览、下载文件等Web应用。

HTTPS流量:HTTPS是HTTP的安全版本,使用SSL(安全套接字层)或TLS(传输层安全)协议加密通信。HTTPS流量通常用于安全的Web传输,例如在线银行、电子商务等。

DNS流量:DNS(域名系统)用于将域名与IP地址相互映射。DNS流量通常用于解析域名、获取IP地址等。

FTP流量:FTP(文件传输协议)用于在客户端和服务器之间传输文件。FTP流量通常用于文件上传、下载等。

SSH流量:SSH(安全壳层)是一种加密的网络协议,用于安全和远程登录。SSH流量通常用于安全的远程管理和文件传输。

这些网络流量类型在不同的应用场景和协议中扮演着不同的角色。分析和监控不同类型的网络流量可以帮助管理员了解网络使用情况、排查故障并优化网络性能。

Linux下监控网络流量的目的

Linux下监控网络流量的目的有多个:

总而言之,监控网络流量可以提高网络性能、保障网络安全、管理网络资源、控制成本和故障排查,对于维护良好的网络运行非常重要。

有哪些专门的工具和技术分析网络流量

要实现Linux上的网络流量分析,可以使用一些专门的工具和技术。下面是一些常用的方法和原理:

这些工具的实现原理都涉及到网络协议、socket编程、数据包的捕获和解析等知识。具体来说,抓包工具通过监听网络接口,将接收到的数据包保存到文件中;流量监控工具通过读取接口的流量数据并进行统计和展示;数据包分析工具和流量分析工具则依靠网络协议和数据包的解析来提供更深入的分析功能。

总体来说,实现网络流量分析需要一定的网络知识和编程技巧,同时需要使用相关工具和技术进行数据的捕获、解析和分析。

在Linux文件系统的/proc目录下分析网络流量

在Linux文件系统的/proc目录下,可以找到一些与网络流量相关的信息。以下是一些常见的文件和目录:

/proc/net/dev:这个文件提供了网络设备的收发网络流量统计信息,包括每个网络接口的接收和发送数据包数量、错误统计、丢弃的数据包数量等。

使用cat或者less命令:你可以使用cat或者less命令来查看/proc下的文件内容,例如:cat /proc/net/dev可以查看网络设备的收发网络流量统计信息。

使用awk或者sed命令进一步处理:你可以使用awk或者sed命令来处理和过滤数据,例如:cat /proc/net/dev | awk '{print $1, $2}'可以只打印出网络设备名称和接收流量的统计值.

/proc/net/tcp:这个文件提供了当前TCP连接的详细信息,包括本地和远程IP地址、端口号,连接状态,以及一些统计信息。
使用grep命令筛选:你可以使用grep命令来筛选你感兴趣的信息,例如:grep "ESTABLISHED" /proc/net/tcp可以查看当前所有TCP连接中状态为ESTABLISHED的连接信息。

/proc/net/udp:类似于/proc/net/tcp文件,提供了当前UDP连接的详细信息。

/proc/net/raw:提供了当前原始套接字(RAW socket)的相关信息,包括本地和远程IP地址、协议类型等。

/proc/net/snmp:提供了简单网络管理协议(SNMP)相关的统计信息,包括接口、IP、TCP、UDP等各层的统计信息。

/proc/net/ip_conntrack:如果系统启用了连接跟踪(conntrack)功能,这个文件提供了关于当前连接的跟踪信息,包括连接状态、源IP地址、目的IP地址、端口号等。

这些文件提供了一些基本的网络流量统计和连接信息,可以通过读取这些文件进行分析和监控。想要更加深入和详细地分析网络流量,则需要使用更专业的网络流量分析工具。

Linux C/C++ 网络流量分析

代码中网络流量分析是一个用于网络统计的命令行工具,用于监视系统网络接口的流量、带宽使用情况以及与网络相关的统计数据。它可以提供网络传输的各种统计信息,包括数据包的数量、字节数、错误、丢包等。

/*
 * 接口统计信息
 */
typedef struct nic_stats {
	struct timeval tv;		/* tv_sec, tv_usec */
	uint64_t rbytes;		/* total read bytes */
	uint64_t wbytes;		/* total written bytes */
	uint64_t rpackets;		/* total read packets */
	uint64_t wpackets;		/* total written packets */
	uint64_t ierr;			/* total input errors */
	uint64_t oerr;			/* total output errors */
	uint64_t coll;			/* total collisions */
	uint64_t nocp;			/* total nocanput */
	uint64_t defer;			/* total defers */
	uint64_t sat;			/* saturation value */
} nicstats_t;
/*
 * print_header - 打印标题行
 */
static void
print_header(void)
{
	if (g_style)
		(void) printf("%8s %5s %14s %14s\n",
		    "Time", "Int", "rKb/s", "wKb/s");
	else
		(void) printf(
		    "%8s %5s %7s %7s %7s %7s %7s %7s %7s %7s\n",
		    "Time", "Int", "rKb/s", "wKb/s", "rPk/s",
		    "wPk/s", "rAvs", "wAvs", "%Util", "Sat");
}
static int split_ifname(char *if_name, char *drv, uint32_t *instance)
{
...
	n = 0;
	for (p = if_name; *p; p++)
		n++;
	if (n <= 1)
		return (B_FALSE);
	m = n;
	for (p--; isdigit(*p); p--)
		n--;
	if (m == n || n == 0)
		return (B_FALSE);
	(void) strncpy(drv, if_name, n);
	drv[n] = '\0';
	*instance = (uint32_t)atol(++p);
...
}
...
static void update_ksp_by_type(kstat_t **kspp, uint32_t types, char *name)
{
...
	if (types & KS_LINK) 
	{
		*kspp = fetch_ksp("link", 0, name);
		return;
	}
	(void) split_ifname(name, drv, &instance);
	if (types & KS_DRV_MAC) 
	{
		*kspp = fetch_ksp(drv, instance, "mac");
		return;
	}
	if (types & KS_DIN) 
	{
		*kspp = fetch_ksp(drv, instance, name);
		return;
	}
	if (types & KS_DRV) {
		*kspp = fetch_ksp(drv, instance, NULL);
		return;
	}
	if (types & KS_NAME) {
		*kspp = fetch_ksp(name, -1, NULL);
		return;
	}
	...
}
static void update_stats(void)
{
...
	(void) gettimeofday(&now_tv, NULL);
	if (g_tcp) 
	{
		/* 更新TCP统计信息 */
		if (g_new_kstat_chain) 
		{
			g_tcp_ksp = kstat_lookup(g_kc, "tcp", -1, "tcp");
			if (! g_tcp_ksp)
				die(1, "kstat_lookup");
		}
		if (kstat_read(g_kc, g_tcp_ksp, NULL) < 0)
			die(1, "kstat_read");
		g_tcp_new->tv.tv_sec = now_tv.tv_sec;
		g_tcp_new->tv.tv_usec = now_tv.tv_usec;
		TCP_UPDATE(inDataInorderSegs, "inDataInorderSegs");
		TCP_UPDATE(outDataSegs, "outDataSegs");
		TCP_UPDATE(inDataInorderBytes, "inDataInorderBytes");
		TCP_UPDATE(inDataUnorderSegs, "inDataUnorderSegs");
		TCP_UPDATE(inDataUnorderBytes, "inDataUnorderBytes");
		TCP_UPDATE(outDataBytes, "outDataBytes");
		TCP_UPDATE(estabResets, "estabResets");
		TCP_UPDATE(outRsts, "outRsts");
		TCP_UPDATE(attemptFails, "attemptFails");
		TCP_UPDATE(retransBytes, "retransBytes");
		TCP_UPDATE(passiveOpens, "passiveOpens");
		TCP_UPDATE(activeOpens, "activeOpens");
		TCP_UPDATE(halfOpenDrop, "halfOpenDrop");
		TCP_UPDATE(listenDrop, "listenDrop");
		TCP_UPDATE(listenDropQ0, "listenDropQ0");
	}
	if (g_udp) 
	{
		/* 更新UDP统计信息 */
		if (g_new_kstat_chain) 
		{
			g_udp_ksp = kstat_lookup(g_kc, "udp", -1, "udp");
			if (! g_udp_ksp)
				die(1, "kstat_lookup");
		}
		if (kstat_read(g_kc, g_udp_ksp, NULL) < 0)
			die(1, "kstat_read");
		g_udp_new->tv.tv_sec = now_tv.tv_sec;
		g_udp_new->tv.tv_usec = now_tv.tv_usec;
		UDP_UPDATE(inDatagrams, "inDatagrams");
		UDP_UPDATE(outDatagrams, "outDatagrams");
		UDP_UPDATE(inErrors, "inErrors");
		UDP_UPDATE(outErrors, "outErrors");
	}
	if (g_style == STYLE_NONE && ! g_list)
		return;
	/* 更新接口统计信息 */
	for (nicp = g_nicdatap; nicp; nicp = nicp->next) 
	{
		if (! (nicp->flags & NIC_UP))
			/* 链接未打开 */
			continue;
		if (g_nonlocal && (nicp->flags & NIC_LOOPBACK))
			continue;
		if (! (nicp->flags & NIC_OK_UPDATED))
			if (kstat_read(g_kc, nicp->op_ksp, NULL) < 0)
				die(1, "kstat_read");
		/* 保存网络值 */
		nicp->new.tv.tv_sec = now_tv.tv_sec;
		nicp->new.tv.tv_usec = now_tv.tv_usec;
		nicp->new.rbytes =
			fetch6432(nicp->op_ksp, "rbytes64", "rbytes", 0);
		nicp->new.wbytes =
			fetch6432(nicp->op_ksp, "obytes64", "obytes", 0);
		nicp->new.rpackets =
			fetch6432(nicp->op_ksp, "ipackets64", "ipackets", 0);
		nicp->new.wpackets =
			fetch6432(nicp->op_ksp, "opackets64", "opackets", 0);
		switch (g_style) 
		{
		case STYLE_EXTENDED_PARSEABLE:
		case STYLE_EXTENDED:
			nicp->new.ierr = fetch32(nicp->op_ksp, "ierrors", 0);
			nicp->new.oerr = fetch32(nicp->op_ksp, "oerrors", 0);
			/*FALLTHROUGH*/
		case STYLE_FULL:
		case STYLE_SUMMARY:
			nicp->new.coll = fetch32(nicp->op_ksp, "collisions",
				0);
			nicp->new.nocp = fetch_nocanput(nicp->op_ksp, 0);
			nicp->new.defer = fetch32(nicp->op_ksp, "defer_xmts",
				0);
			nicp->new.sat = nicp->new.defer + nicp->new.nocp +
				nicp->new.coll;
			nicp->new.sat += fetch32(nicp->op_ksp, "noxmtbuf", 0);
			break;
		}
		nicp->speed = fetch64(nicp->op_ksp, "ifspeed", 0);
		nicp->duplex = fetch32(nicp->op_ksp, "link_duplex", 0);
	}
...
}
static void load_snmp(FILE *snmp)
{
...
	/* 从/proc/net/snmp加载TCP和/或UDP统计信息 */
...
	while (remaining) 
	{
		p = fgets(buf, sizeof (buf), snmp);
		if (! p)
			break;
		if (g_tcp && strncmp("Tcp: RtoAlgorithm RtoMin RtoMax MaxConn "
				"ActiveOpens PassiveOpens AttemptFails "
				"EstabResets CurrEstab InSegs OutSegs "
				"RetransSegs InErrs OutRsts", p, 141) == 0) 
				{
			int n;
			n = fscanf(snmp, "Tcp: %lld %lld %lld %lld "
			    "%lld %lld %lld %lld %lld %lld "
			    "%lld %lld %lld %lld\n",
			    &ll[0], &ll[1], &ll[2], &ll[3],
			    &ll[4], &ll[5], &ll[6], &ll[7],
			    &ll[8], &ll[9], &ll[10], &ll[11],
			    &ll[12], &ll[13]);
			if (n == 14) 
			{
				g_tcp_new->inDataInorderSegs = ll[9];
				g_tcp_new->outDataSegs = ll[10];
				g_tcp_new->estabResets = ll[7];
				g_tcp_new->outRsts = ll[13];
				g_tcp_new->attemptFails = ll[6];
				/* Note: bytes */
				g_tcp_new->retransBytes = ll[11];
				g_tcp_new->passiveOpens = ll[5];
				g_tcp_new->activeOpens = ll[4];
			}
			remaining--;
		} 
		else if (g_udp && strncmp("Udp: InDatagrams NoPorts "
				"InErrors OutDatagrams RcvbufErrors "
				"SndbufErrors\n", p, 72) == 0) 
				{
			int n;
			n = fscanf(snmp, "Udp: %lld %lld %lld %lld "
			    "%lld %lld\n",
			    &ll[0], &ll[1], &ll[2], &ll[3],
			    &ll[4], &ll[5]);
			if (n == 6) 
			{
				g_udp_new->inDatagrams = ll[0];
				g_udp_new->outDatagrams = ll[3];
				g_udp_new->inErrors = ll[2]; /* + ll[4]? */
				g_udp_new->outErrors = ll[5];
			}
			remaining--;
		}
	}
}
...
static void update_timestr(time_t *tptr)
{
...
	if (tptr)
		t = *tptr;
	else
		t = time(NULL);
	tm = localtime(&t);
	(void) strftime(g_timestr, sizeof (g_timestr), "%H:%M:%S", tm);
}
static void sleep_for(hrtime_t period, hrtime_t start_n)
{
...
	do 
	{
		pause_tv.tv_sec = pause_n / NANOSEC;
		pause_tv.tv_nsec = pause_n % NANOSEC;
		status = nanosleep(&pause_tv, (struct timespec *)NULL);
		if (status < 0)
			if (errno == EINTR)
			 {
				now_n = gethrtime();
				pause_n = start_n + period - now_n;
				if (pause_n < 100)
					return;
			}
			 else 
			{
				...
			}
	} while (status != 0);
}
...

If you need the complete source code, please add the WeChat number (c17865354792)

运行结果:

Time列:表示当前采样的响应时间.

Int: 网卡名称.

rKB/s : 每秒接收到千字节数.

wKB/s : 每秒写的千字节数.

rPk/s : 每秒接收到的数据包数目.

wPk/s : 每秒写的数据包数目.

rAvs : 接收到的数据包平均大小.

wAvs : 传输的数据包平均大小.

%Util : 网卡利用率(百分比).

Sat : 网卡每秒的错误数.网卡是否接近饱满的一个指标.尝试去诊断网络问题的时候,推荐使用-x选项去查看更多的统计信息.

这将显示ens33接口的流量、带宽使用情况以及其他统计数据:

监控所有网络接口的统计信息,同时显示TCP和UDP连接相关的统计信息:

总结

网络流量分析需要一定的技术知识和经验,但通过学习和实践,我们可以掌握这个技能,更好地管理和维护网络环境。

以上就是Linux C/C++实现网络流量分析工具的详细内容,更多关于C/C++网络流量分析的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文