精华内容
下载资源
问答
  • 一种基于linux系统的精准流量统计方法

    千次阅读 多人点赞 2019-06-25 10:53:50
    linux系统关于流量统计,已经有开源的工具,比如nethogs,nload和iptraf。它们适合我们在PC上直接监控某台设备的流量情况,但并不适合我们应用到自己的程序中去。如果要在自己代码中实现流量的统计,可以有下面几...

    前言:

        在linux系统关于流量统计,已经有开源的工具,比如nethogs,nload和iptraf。它们适合我们在PC上直接监控某台设备的流量情况,但并不适合我们应用到自己的程序中去。如果要在自己代码中实现流量的统计,可以有下面几种方法:统计应用层流量;使用tcpdump抓取每一包数据进行统计;使用Iptables命令来实现。下面就这几种方法进行对比:

    (1)应用层计算流量

        该方法也就是在自己程序中的每个end和recv函数中去实现,统计自己每次进行网络通信时候数据的接收和发送长度,进而统计出总的数据流量。这种方法是一种粗略的计算,实际上是非常不准确的,它比实际的数据流量统计少了。因为我们的send和recv函数是在应用层。应用层的数据,到链路层,中间需要经过传输层和网络层,他们会对数据进程封装,加上数据包头,校验等等信息之后才会到链路层,所以实际链路层发送的数据比应用层的数据要多一些额外的数据,接收数据的时候其实也是一样,只是整个流程反过来了。另外,在网络传输的过程中,还可能出现数据的丢失,这个在有线传输中出现比较少,但是在无线传输并且网络状态不是很好的情况下,出现数据丢失数据重传的概率是非常高的,而在应用层的send和recv函数并不能感知到数据的丢失和重传,所以在应用层统计的流量是不准确的,它会比实际的数据流量统计少了,实际少多少,这个跟网络状态和传输方式有关。实际网络运营商统计的数据流量,是链路层的数据流量,而不是应用层的网络流量。

    (2)tcpdump抓数据

        tcpdump是与Windows系统的wireshark类似的一个网络抓包工具。它可以感知链路层数据的丢失和重传等等信息,但是它是基于数据截取的方式来获取信息,这样的方式比较比较影响网络的性能,同时也是比较消耗系统的资源,可以用来做网络调试,但不是非常适合网络流量的统计。

    (3)使用iptables统计流量

        iptables命令 是Linux上常用的防火墙软件,是netfilter项目的一部分。它可以根据不同的规则对数据进行过滤,转发和统计。它可以针对某一个IP或是多个IP进程处理,也可以针对某一个端口进行处理。当它做数据统计的时候,它的数值统计的是链路层的数据。也就是包括了IP包信息和数据重传等额外数据的长度。通过这种方式,可以实现流量的精准统计。

     

    设计思路:

        基本设计方法是这样:在一个进程(进程A)中循环检测有那些Ip和端口需要添加进Iptable的统计规则中,如果有收到一个添加规则的请求,则判断该规则是否已经添加进Iptable中,如果没有则添加,如果有则放弃此次规则的添加。在其他的进程中,比如进程B,C,D,E...,在进程网络连接的时候,根据需求将需要统计的IP或是端口信息,发送给进程A,让进程A去进行iptables规则的添加。另外,在进程A中,可以循环的去获取Iptables统计的流量,还可以实时的去获取网卡实际收发的数据,实现网络流量的实时更新。进程A,B,C,D,E之间,可以使用进程间通信的任意一种,这里为了方便扩展,使用了命名管道进程通信。为了方便数据检验传递和处理,在进程间传递的IP地址可以转换为数值二不是字符串,实际在connet函数建立网络连接的时候,使用的也是一个32位的int类型数据来表示IP地址。

     

    功能实现:

    (1)iptables规则添加

        这里只统计IP,不进行端口的统计,使用一个数组来记录需要添加进iptables的规则,规则命令如下:

        /**统计IP 192.168.20.38 的数据输入**/
        iptables -I INPUT  -d 192.168.20.38
        /***统计IP 192.168.20.38 的数据输出**/
        iptables -I OUTPUT -s 192.168.20.38

        可以使用iptables --list 查看实际添加的规则:

    Chain INPUT (policy ACCEPT)
    target     prot opt source               destination         
               all  --  anywhere             192.168.20.38       
    
    Chain FORWARD (policy ACCEPT)
    target     prot opt source               destination         
    
    Chain OUTPUT (policy ACCEPT)
    target     prot opt source               destination         
               all  --  192.168.20.38        anywhere    

    (2)Iptable的流量查看:

        可以使用命令:iptables -n -v -L -t filter -x 查看iptables的流量统计情况:

    biao@ubuntu:~/test/nettraffic/NetTrafficStatis/Process1$ sudo iptables -n -v -L -t filter -x
    Chain INPUT (policy ACCEPT 5147 packets, 654051 bytes)
        pkts      bytes target     prot opt in     out     source               destination         
           0        0            all  --  *      *       0.0.0.0/0            192.168.20.38       
    
    Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
        pkts      bytes target     prot opt in     out     source               destination         
    
    Chain OUTPUT (policy ACCEPT 2810 packets, 5760828 bytes)
        pkts      bytes target     prot opt in     out     source               destination         
           0        0            all  --  *      *       192.168.20.38        0.0.0.0/0           
    biao@ubuntu:~/test/nettraffic/NetTrafficStatis/Process1$ 

    (3)网卡流量查看:

        在linux系统中,我们可以通过proc虚拟文件系统获取linux系统的一些信息,其中就包括网卡信息,在Ubuntu16.04系统中/sys/class/net/ens33/statistics/目录下的文件就记录了网卡的收发数据量,所发数据包数等等信息。
    查看本次开机网卡总共发送的数据量:

    biao@ubuntu:~/test/nettraffic/NetTrafficStatis/Process1$ cat /sys/class/net/ens33/statistics/tx_bytes
    12219392
    biao@ubuntu:~/test/nettraffic/NetTrafficStatis/Process1$ 

        查看本次开机网卡总共接收的数据量:

    biao@ubuntu:~/test/nettraffic/NetTrafficStatis/Process1$ cat /sys/class/net/ens33/statistics/rx_bytes
    6351838
    biao@ubuntu:~/test/nettraffic/NetTrafficStatis/Process1$

    (4)进程间通行

        这里使用的是命名管道,在使用命名管道的时候,需要注意管道的阻塞和非阻塞模式,这里接收和发送都是采用的非阻塞模式,另外,还需要注意管道的收发数据规则。在接收进程从,非阻塞方式打开,可以正常打开,接收数据也会立即返回。在发送端非阻塞方式打开,如果这条管道,没有一个进程在接收,那么在发送端打开管道会返回失败。如果有多个进程进程进行数据写入,但是只有一个进程在进行读操作的时候,要注意读写数据的原子性操作。

        我们这里是针对特定IP进程流量的统计,在不同进程之间,我们需要把Ip地址信息发送给进程A进程Iptable规则的添加,这里我们使用的是重新封装connet函数,在connet函数中,我们可以获取到需要建立网络链接的IP地址的一个32位10进制数值,我们可以直接将该值传递给进程A,进程A再将该10进制的数值装换为字符串类型的Ip地址。

    (5)代码实现:

    (a)进程A中iptable规则添加,流量获取实现:

    /************************************************************
    *Copyright (C), 2017-2027,lcb0281at163.com lcb0281atgmail.com
    *FileName: NetTrafficStati.cpp
    *Date:     2019-06-22
    *Author:   Caibiao Lee
    *Version:  V1.0
    *Description:网络流量统计
    *Others:
    *History:
    ***********************************************************/
    #include <string.h>
    #include <stdio.h>       
    #include <stdlib.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/types.h> 
    #include <sys/stat.h>
    
    #include "IPAddrInterFace.h"
    #include "NetTrafficStati.h"
    
    #define IPTABLE_RES_FILE 	"/tmp/iptable_res"
    #define READ_IPTABLE		"iptables -n -v -L -t filter -x | grep -E \"Chain OUTPUT|Chain INPUT\">/tmp/iptable_res"
    
    /******************************************************** 
    Function:	 NetTrafficStati
    Description: 构造函数
    Input:	none
    OutPut: none
    Return: none
    Others: 
    Author: Caibiao Lee
    Date:	2019-06-21
    *********************************************************/
    NetTrafficStati::NetTrafficStati()
    {
    	m_pstIpTable = &m_stIpTable;
    	m_s32PipeFileID = -1;
    	
    	IpTable_Init(m_pstIpTable);
    	memset(&m_stFlowCount,0,sizeof(m_stFlowCount));
    }
    
    /******************************************************** 
    Function:	 ~NetTrafficStati
    Description: 析构函数
    Input:	none
    OutPut: none
    Return: none
    Others: 
    Author: Caibiao Lee
    Date:	2019-06-21
    *********************************************************/
    NetTrafficStati::~NetTrafficStati()
    {
    
    }
    
    /******************************************************** 
    Function:	 NTS_Instance
    Description: 获取静态对象
    Input:	none
    OutPut: none
    Return: none
    Others: 
    Author: Caibiao Lee
    Date:	2019-06-21
    *********************************************************/
    NetTrafficStati *NetTrafficStati::NTS_Instance()
    {
        static NetTrafficStati * pClsInstance = NULL;
        if (pClsInstance == NULL)
        {
            pClsInstance = new NetTrafficStati();
        }
        return pClsInstance;
    
    }
    
    /************************************************* 
    Function:    IpTable_Init  
    Description: 初始化IP列表
    Input:   stIpTable   
    Return: stIpTable
    Others: 
    Author: Caibiao Lee
    Date:   2019.06.21
    *************************************************/
    int NetTrafficStati::IpTable_Init(IP_TABLE_S *stIpTable)
    {
    	memset((char*)stIpTable,0,sizeof(IP_TABLE_S));	
    	stIpTable->u8InitFlag = 1;
    
    	return 0;
    }
    
    /************************************************* 
    Function:    IpTable_Check  
    Description: 检测IpNumIP是否已经存在于IP列表中
    Input:   IpNum 需要检测的IP值   
    Return:  0 IP 列表中没有该IP,非0,已经存在该IP
    Others: 
    Author: Caibiao Lee
    Date:   2019.06.21
    *************************************************/
    int NetTrafficStati::IpTable_Check(IP_TABLE_S *stIpTable,unsigned int IpNum)
    {
    	if(NULL==stIpTable)
    	{
    		printf("Error:input stIpTable is NULL \n");
    		return -1;
    	}
    	
    	for(int i=0;i<stIpTable->u8UsedIpCount;i++)
    	{
    		/**已经存在该IP**/
    		if(IpNum==stIpTable->u32IPAddrNum[i])
    		{
    			return -1;
    		}
    	}
    	
    	return 0;
    }
    
    /************************************************* 
    Function:    IpTable_Add  
    Description: 插入一个IP到IP列表中
    Input: stIpTable IP 列表, IpNum IP 号
    Return:
    Others: 0 插入成功,非0,插入失败
    Author: Caibiao Lee
    Date:   2019.06.21
    *************************************************/
    int NetTrafficStati::IpTable_Add(IP_TABLE_S *stIpTable,unsigned int IpNum)
    {
    	if(NULL==stIpTable)
    	{
    		printf("Error:input stIpTable is NULL \n");
    		return -1;
    	}
    	/**判断IP表是否初始化**/
    	if(1!=stIpTable->u8InitFlag)
    	{
    		IpTable_Init(stIpTable);
    	}
    	
    	/**检测IpNum 是否已经存在于IP表中**/
    	if(0==IpTable_Check(stIpTable,IpNum))
    	{	
    		/**添加IpNum 到IP表中**/
    		if(stIpTable->u8UsedIpCount < MAX_IP_COUNT)
    		{
    			stIpTable->u32IPAddrNum[stIpTable->u8UsedIpCount] = IpNum;
    			stIpTable->u8UsedIpCount++;	
    			printf("add IP %u OK \n",IpNum);
    			return 0;
    		}else
    		{
    			IpTable_Init(stIpTable);
    			stIpTable->u32IPAddrNum[stIpTable->u8UsedIpCount] = IpNum;
    			stIpTable->u8UsedIpCount++;	
    			printf("add IP %u OK \n",IpNum);
    			return 0;
    		}
    	}else
    	{
    		printf("ip %d is already set \n",IpNum);
    		return -2;
    	}
    	
    	return -3;
    
    }
    
    /************************************************* 
    Function:    iptables_rulesAdd  
    Description: 将该IP添加到iptables的规则中
    Input: stIpTable IP 列表, IpNum IP 号
    Return:
    Others: 0 插入成功,非0,插入失败
    Author: Caibiao Lee
    Date:   2019.06.21
    *************************************************/
    int NetTrafficStati::iptables_rulesAdd(struct sockaddr_in *addr)
    {
    	int  l_s32Ret = 0;
    	char l_arrs8IPdotdec[20] = {0}; // 存放点分十进制IP地址
    	char l_IptablesCmd[64] = {0};
    
    	if(AF_INET!=addr->sin_family)//IPv6
    	{
    		return -1;
    	}
    
    	if(0==IpTable_Add(m_pstIpTable,addr->sin_addr.s_addr))
    	{
    
    		if(NULL!=inet_ntop(AF_INET,&addr->sin_addr,l_arrs8IPdotdec,16));
    		{
    			/**set input rule**/
    			snprintf(l_IptablesCmd,sizeof(l_IptablesCmd),"iptables -I INPUT -d %s ",l_arrs8IPdotdec);
    			printf("cmd : %s \n",l_IptablesCmd);
    			system(l_IptablesCmd);
    			
    			/**set output rule**/
    			memset(l_IptablesCmd,0,sizeof(l_IptablesCmd));
    			snprintf(l_IptablesCmd,sizeof(l_IptablesCmd),"iptables -I OUTPUT -s %s ",l_arrs8IPdotdec);
    			printf("cmd : %s \n",l_IptablesCmd);
    			system(l_IptablesCmd);
    
    			printf("add IP: %s is OK\n",l_arrs8IPdotdec);
    			l_s32Ret = 0;
    		}		
    	}else
    	{
    		if(NULL!=inet_ntop(AF_INET,&addr->sin_addr,l_arrs8IPdotdec,16))
    		{
    			printf("IP: %s is in the Iptable \n",l_arrs8IPdotdec);
    		}
    		
    		l_s32Ret = -1;
    	}
    	
    	return l_s32Ret;
    
    }
    
    
    /************************************************* 
    Function:    NTS_GetNetWorkCardFlow  
    Description: 读取网卡流量
    Input: u64Count
    Output:u64Count
    Return: 0 成功,非0,失败
    Others: 
    Author: Caibiao Lee
    Date:   2019.06.21
    *************************************************/
    int NetTrafficStati::NTS_GetNetWorkCardFlow(unsigned long long *u64Count)
    {
    	int l_s32Ret = 0;
    	FILE *l_pFd = NULL;
    	char * line = NULL;
    	size_t len = 0;
    	ssize_t read;
    	unsigned long long l_u64ReadTx = 0;
    	unsigned long long l_u64ReadRx = 0;
    
    	l_pFd=fopen(NETWORK_CARD_TX,"r");
    
    	if(NULL!=l_pFd)
    	{
    		if((read = getline(&line, &len, l_pFd)) != -1)
    		{
    			sscanf(line,"%lld ",&l_u64ReadTx);
    			printf("read Tx %lld Byte \n",l_u64ReadTx);
    		}
    
    		if(NULL!=l_pFd)
    		{
    			fclose(l_pFd);
    			l_pFd = NULL;
    		}
    	    
    	    if (NULL!=line)
    		{
    			free(line);
    			line = NULL;
    		}
    	}else
    	{
    		printf("open %s error ! \n",NETWORK_CARD_TX);
    		l_s32Ret = -1;
    	}
    
    	l_pFd=fopen(NETWORK_CARD_RX,"r");
    	if(NULL!=l_pFd)
    	{
    		if((read = getline(&line, &len, l_pFd)) != -1)
    		{
    			sscanf(line,"%lld ",&l_u64ReadRx);
    			printf("read Rx %lld Byte \n",l_u64ReadRx);
    		}
    
    		if(NULL!=l_pFd)
    		{
    			fclose(l_pFd);
    			l_pFd = NULL;
    		}
    	    
    	    if (NULL!=line)
    		{
    			free(line);
    			line = NULL;
    		}
    	}else
    	{
    		printf("open %s error ! \n",NETWORK_CARD_TX);
    		l_s32Ret = -2;
    	}
    
    	*u64Count = l_u64ReadTx + l_u64ReadRx;
    
    	return l_s32Ret;
    
    }
    
    /************************************************* 
    Function:    NTS_ReadIptableIOByte  
    Description: 读取IPTable统计到的流量
    Input: u64Count
    Output:none
    Return:0 成功,非0,失败
    Others:
    Author: Caibiao Lee
    Date:   2019.06.21
    *************************************************/
    int NetTrafficStati::NTS_ReadIptableIOByte(unsigned long long *u64Count)
    {
    	FILE * fp;
    	char * line = NULL;
    	size_t len = 0;
    	char str1[16] = {0};
    	char str2[16] = {0};
    	char str3[16] = {0};
    	char str4[16] = {0};
    	char str5[16] = {0};
    	char str6[16] = {0};
    	unsigned long long num1 = 0;
    	unsigned long long num2 = 0;
    	unsigned long long l_u64DataByte = 0;
    	ssize_t read;
    	
    	//printf("cmd = %s \n",READ_IPTABLE);
    	system(READ_IPTABLE);
    	
        fp = fopen(IPTABLE_RES_FILE, "r");
        if (NULL==fp)
    	{
    		printf("open file: %s error \n",IPTABLE_RES_FILE);
    		return -1;
    	}
           
        while ((read = getline(&line, &len, fp)) != -1) 
    	{
    		sscanf(line,"%s %s %s %s %lld %s %lld %s ",str1,str2,str3,str4,&num1,str5,&num2,str6);
    		l_u64DataByte += num2;
        }
    	
    	if(NULL!=fp)
    	{
    		fclose(fp);
    		fp = NULL;
    	}
        
        if (NULL!=line)
    	{
    		free(line);
    		line = NULL;
    	}
    
    	*u64Count = l_u64DataByte;
    	
    	return 0;
    
    }
    
    /************************************************* 
    Function:    NTS_GetIpFromPipe  
    Description: 从管道中获取IP信息,判断是否存在IP列表中
    	如果不存在,这添加进IP列表,并添加Iptable规则
    Input: none
    Output:none
    Return:0 成功,非0,失败
    Others: 注意这里的管道,在该进程中,以非阻塞的方式打开
    	,打开以后不能关闭操作,如果关闭,写管道会打不开
    Author: Caibiao Lee
    Date:   2019.06.21
    *************************************************/
    int NetTrafficStati::NTS_GetIpFromPiPe(void)
    {
    	int  l_s32Ret = 0;
        int  l_s32PipeFd = -1;
    	int  l_s32DataLen = -1;
    	int  l_s32ReadPos = -1;
    	int  l_s32SendCount = 3;
        char l_arrs8Buffer[128] = {0};
    	IP_ADDR_NUM_S l_stIpAddr = {0};
    	struct sockaddr_in stIpAdr = {0};
    	struct sockaddr_in *stpIpAdr = &stIpAdr;
    
    	/**判断管道是否存在**/
        if(access(PIPE_NAME, F_OK) == -1)
        {
            printf ("Create the fifo pipe.\n");
            l_s32Ret = mkfifo(PIPE_NAME, 0777);
     
            if(l_s32Ret != 0)
            {
                fprintf(stderr, "Could not create fifo %s\n", PIPE_NAME);
               	return l_s32Ret;
            }
        }
    
    	if(-1 ==m_s32PipeFileID)
    	{
    		l_s32PipeFd = open(PIPE_NAME, O_NONBLOCK|O_RDONLY);
    		m_s32PipeFileID = l_s32PipeFd;
    	}
    	/**以非阻塞的方式去打开管道**/
        
        if(m_s32PipeFileID !=-1)
        {
        	l_s32DataLen = 0;
    		l_s32ReadPos = 0;
    		l_s32DataLen = read(m_s32PipeFileID, l_arrs8Buffer, sizeof(l_arrs8Buffer));
    		while(l_s32DataLen > 0)
    		{
    			if(l_s32DataLen>=sizeof(IP_ADDR_NUM_S))
    			{
    				memcpy(&l_stIpAddr,&l_arrs8Buffer[l_s32ReadPos],sizeof(IP_ADDR_NUM_S));
    				l_s32ReadPos += sizeof(IP_ADDR_NUM_S);
    				l_s32DataLen -= sizeof(IP_ADDR_NUM_S);
    
    				if((IP_START_FLAG==l_stIpAddr.u8StartFlag)&&(IP_END_FLAG==l_stIpAddr.u8EndFlag))
    				{
    					stIpAdr.sin_family = AF_INET;  //设置地址家族
    					//stIpAdr.sin_port = htons(800);  //设置端口
    					stIpAdr.sin_addr.s_addr = l_stIpAddr.u32IPAddrNum;  //设置地址
    					//printf("IP ddr NUM = %u \n",l_stIpAddr.u32IPAddrNum);
    					iptables_rulesAdd(stpIpAdr);
    					l_s32Ret = 0;
    				}
    			}
    		}
        }
    	else
    	{
    		printf("open pipe errror !\n");
    		l_s32Ret  = -1;
    	}
    
    	/**不关闭**/
    	//close(m_s32PipeFileID);
    
    	return 0;
    }
    
    /************************************************* 
    Function:    NTS_GetIpFromPipe  
    Description: 从管道中获取IP信息,判断是否存在IP列表中
    	如果不存在,这添加进IP列表,并添加Iptable规则
    Input: none
    Return:
    Others: 该函数需要被业务进程周期调用,建议1S调用一次
    Author: Caibiao Lee
    Date:   2019.06.21
    *************************************************/
    int NetTrafficStati::NTS_AddIpToIPTable(void)
    {
    	NTS_GetIpFromPiPe();	
    }
    
    
    /************************************************* 
    Function:    NTS_UpdateFlowData  
    Description: 流量统计更新
    Input: none
    Return:
    Others: 该函数需要被业务进程周期调用,建议1S调用一次
    Author: Caibiao Lee
    Date:   2019.06.21
    *************************************************/
    int NetTrafficStati::NTS_UpdateFlowData(void)
    {
    	int l_s32Ret = 0;
    	unsigned long long l_u64NetWorkCardFlow  = 0;
    	unsigned long long *l_pu64NetWorkCardFlow = &l_u64NetWorkCardFlow;
    
    	unsigned long long l_u64IptableIOByte  = 0;
    	unsigned long long *l_pu64IptableIOByte = &l_u64IptableIOByte;
    
    	if(0==NTS_GetNetWorkCardFlow(l_pu64NetWorkCardFlow))
    	{
    		printf("l_pu64NetWorkCardFlow = %lld \n",l_u64NetWorkCardFlow);
    		m_stFlowCount.u64NetWorkCount = l_u64NetWorkCardFlow;
    	}
    
    	if(0==NTS_ReadIptableIOByte(l_pu64IptableIOByte))
    	{
    		printf("l_pu64IptableIOByte = %lld \n",l_u64IptableIOByte);
    		m_stFlowCount.u64IptableCount= l_u64IptableIOByte;
    	}
    	
    }
    
    
    

    (b)重新封装connet 函数

    /************************************************************
    *Copyright (C), 2017-2027,lcb0281at163.com lcb0281atgmail.com
    *FileName: IPAddrInterFace.cpp
    *Date:     2019-06-22
    *Author:   Caibiao Lee
    *Version:  V1.0
    *Description:IP地址设置和获取模块,注意管道的数据收发规则
    *History:
    ***********************************************************/
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/types.h> 
    #include <sys/stat.h>
    
    
    #include "IPAddrInterFace.h"
    
    /************************************************* 
    Function:    IPAddWriteToPipe  
    Description: 将IP地址写入管道中。
    Input: u32IPAddr
    output:none
    Return:0 成功,非0,失败
    Others:注意命名管道的读写规则
    	1.以非阻塞只写方式打开时,在多进程中同时写入数据,注意写入的原子性。
    	2.以非阻塞只写方式打开时,如果没有一个进程在读管道,打开会失败。
    	3.以非阻塞只写方式打开时,如果所有读管道进程关闭,写进程会收到SIGPIPE信号
    	   如果写进程不对SIGPIPE信号进行处理,会导致写进程退出。
    Author: Caibiao Lee
    Date:   2019.06.21
    *************************************************/
    static int IPAddWriteToPipe(unsigned int u32IPAddr)
    {
    	int  l_s32Ret = 0;
        int  l_s32PipeFd = -1;
    	int  l_s32SendCount = 3;
        char l_arrs8Buffer[32] = {0};
    	IP_ADDR_NUM_S l_stIpAddr = {0};
    
    	/**判断管道是否存在**/
        if(access(PIPE_NAME, F_OK) == -1)
        {
            printf ("Create the fifo pipe.\n");
            l_s32Ret = mkfifo(PIPE_NAME, 0777);
     
            if(l_s32Ret != 0)
            {
                fprintf(stderr, "Could not create fifo %s\n", PIPE_NAME);
               	return l_s32Ret;
            }
        }
    
    	/**以非阻塞的方式去打开管道**/
        l_s32PipeFd = open(PIPE_NAME, O_NONBLOCK|O_WRONLY);
        if(l_s32PipeFd !=-1)
        {
        	l_stIpAddr.u8StartFlag  = IP_START_FLAG;
    		l_stIpAddr.u8EndFlag    = IP_END_FLAG;
    		l_stIpAddr.u32IPAddrNum = u32IPAddr;
    		memcpy(l_arrs8Buffer,&l_stIpAddr,sizeof(IP_ADDR_NUM_S));
    		
    		l_s32Ret = write(l_s32PipeFd, l_arrs8Buffer, sizeof(IP_ADDR_NUM_S));
    		if(l_s32Ret == -1)
    		{
    			while((l_s32SendCount--)>0)
    			{
    				sleep(1);
    				if(-1 != write(l_s32PipeFd, l_arrs8Buffer, sizeof(IP_ADDR_NUM_S)))
    				{
    					l_s32Ret = 0;
    					break;
    				}else
    				{
    					l_s32Ret = -1;
    				}
    			}			
    		}	
        }
    	else
    	{
    		printf("open pipe errror !\n");
    		l_s32Ret  = -1;
    	}
    	
    	close(l_s32PipeFd);
    	
    	return l_s32Ret;
    }
    
    
    /************************************************* 
    Function:    lcb_connect  
    Description: 重新封装connet函数,与connect函数的应用
    			 完全一致
    Input: connect 系统函数的返回值
    Return:
    Others: 在这个函数中,将IP地址的十进制数值写入到管道中
    	通过wsd_GetIpAddr接口获取IP值,以实现去耦合及进程间
    	通行
    Author: Caibiao Lee
    Date:   2019.06.21
    *************************************************/
    int wsd_connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen)
    {
    	int l_s32Ret = 0;
    	unsigned int l_u32IpAddr = 0; 
    	struct sockaddr_in *l_stAddrIn = NULL;
    		
    	l_s32Ret = connect(sockfd,addr,addrlen);
    
    	l_stAddrIn  = (struct sockaddr_in *)addr;
    	l_u32IpAddr = l_stAddrIn->sin_addr.s_addr;
    
    	IPAddWriteToPipe(l_u32IpAddr);
    
    	return l_s32Ret;
    }
    
    

    (c)测试进程代码:

    /************************************************************
    *Copyright (C), 2017-2027,lcb0281at163.com lcb0281atgmail.com
    *FileName: Process1_main.cpp
    *Date:     2019-06-22
    *Author:   Caibiao Lee
    *Version:  V1.0
    *Description:调用wsd_connect接口将IP地址传递给统计进程
    *Others: 
    ***********************************************************/
    #include<stdio.h>       
    #include<stdlib.h>
    #include<string.h>
    #include<errno.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<netinet/in.h>
    #include<termios.h>
    #include<sys/types.h>   
    #include<sys/stat.h>    
    #include<fcntl.h>
    #include<unistd.h>
    #include<sys/ioctl.h>
    #include<signal.h>
    
    #include "IPAddrInterFace.h"
    
    
    #define MAXLINE 256
    #define PORT    6666
    int fd;
    /*
    linux ctrl + C 会产生 SIGINT信号
    接收到SIGINT 信号进入该函数
    */
    void stop(int signo)
    {
        printf("client stop\n");
    	close(fd);  
    	_exit(0);
    }
     
    /*客户端处理函数*/
    void client_process(void)
    {
    	char readbuff[MAXLINE];
    	char writebuff[MAXLINE];
    	char * write = "I am client";
    	int num = 0;
    	
    	while(1)
    	{
    		num = recv(fd,readbuff,MAXLINE,0);/*接收服务端的数据,recv在这里如果没有数据会阻塞*/
    		if(num > 0)
    		{
    			printf("client read data : %s \n",readbuff);
    			send(fd, write, strlen(write)+1, 0); /*接收到数据后再向服务端发送一个字符串*/
    		}
    		else if(num == 0)/*recv返回值为0 的时候表示服务端已经断开了连接*/
    		{
    			stop(1); /*执行退出操作*/
    		}
    	}
    }
     
    int main(int argc, char** argv)
    {
    	struct sockaddr_in server_addr;
    	struct sockaddr_in client_addr;
    	int ret;
     
    	fd = socket(AF_INET,SOCK_STREAM,0);/*建立流式套接字*/
    	if(fd < 0)
    	{
    		printf("clinet socket err \n");
    	}
     
    	/*设置服务端地址*/
    	memset(&server_addr,0,sizeof(server_addr));
    	server_addr.sin_family = AF_INET; 				/*AF_INET表示 IPv4 Intern 协议*/
    	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);/*INADDR_ANY 可以监听任意IP */
    	server_addr.sin_port = htons(PORT);				/*设置端口*/
     
    	inet_pton(AF_INET,"192.168.20.221",&server_addr.sin_addr);/*将用户输入的字符串类型的IP地址转为整型*/
    	//connect(fd,(struct sockaddr*)&server_addr,sizeof(server_addr));/*连接服务器*/
    	wsd_connect(fd,(struct sockaddr*)&server_addr,sizeof(server_addr));/*连接服务器*/
    	signal(SIGINT,stop);	/*注册SIGINT信号*/
    	client_process();		/*进入处理函数*/
    	
    	close(fd);/*关闭文件*/
    	return 0;
    }

    完整工程文件结构:

    biao@ubuntu:~/test/nettraffic/NetTrafficStatis$ tree
    .
    ├── bin
    ├── IPAddrInterFace.cpp
    ├── IPAddrInterFace.h
    ├── main.cpp
    ├── Makefile
    ├── NetTrafficStati.cpp
    ├── NetTrafficStati.h
    ├── Process1
    │   ├── bin
    │   ├── IPAddrInterFace.cpp
    │   ├── IPAddrInterFace.h
    │   ├── Makefile
    │   └── Process1_main.cpp
    └── Process2
        ├── IPAddrInterFace.cpp
        ├── IPAddrInterFace.h
        ├── Makefile
        └── Process2_main.cpp
    
    4 directories, 14 files
    biao@ubuntu:~/test/nettraffic/NetTrafficStatis$ 

      工程代码可以从这里获取:《一种基于linux系统的精准流量统计方法》


        

    展开全文
  • 文件说明: streak.sh:以“K”为流量单位的Linux网卡检测工具。 stream.sh:以“M”为流量单位的Linux网卡检测工具...此工具截取Linux系统文件夹/proc/net/dev中的网卡部分信息并按格式打印。 打印结果与下一次取

    文件说明:
    streak.sh:以“K”为流量单位的Linux网卡检测工具。
    stream.sh:以“M”为流量单位的Linux网卡检测工具。

    使用方法:
    chmod a+x streak.sh stream.sh

    ./streak.sh或./stream.sh

    工具说明:
    此工具截取了Linux系统文件夹/proc/net/dev中的网卡部分信息并按格式打印。
    打印结果与下一次取值进行对比,对比时间间隔为1秒。
    并将取值进行单位换算,得到以K或M为单位的输出。
    加入了read读取网口的环境变量,减小了工作量。

     

    #! /bin/bash
    read -p "Enter your net port:[eth0|eth1|eth2]" ifcfg
    typeset in in_old dif_in dif_in1 dif_out1
    typeset out out_old dif_out
    
    in_old=$(cat /proc/net/dev | grep $ifcfg | sed  's=^.*:==' | awk '{ print $1 }' )
    out_old=$(cat /proc/net/dev | grep $ifcfg | sed  's=^.*:=='  | awk '{ print $9 }')
    
    while true
    do
             sleep 1
             in=$(cat /proc/net/dev | grep $ifcfg | sed  's=^.*:=='  | awk '{ print $1 }')
             out=$(cat /proc/net/dev | grep $ifcfg | sed  's=^.*:=='  | awk '{ print $9 }')
             dif_in=$((in-in_old))
             dif_in1=$((dif_in * 8 / 1024 ))
             dif_out=$((out-out_old))
             echo "                                         IN: ${dif_in} bytes     OUT: ${dif_out} bytes "
             dif_out1=$((dif_out * 8 / 1024 ))
             echo "IN: ${dif_in1} kbps    OUT: ${dif_out1} kbps"
             in_old=${in}
             out_old=${out}
    done
    
    
    #运行效果:
    # ./streak.sh
                                                    IN: 349179 bytes     OUT: 1363936 bytes 
    #IN: 2 kbps    OUT: 10 kbps
                                                    IN: 349612 bytes     OUT: 1361852 bytes 
    #IN: 2 kbps    OUT: 10 kbps
                                                    IN: 348684 bytes     OUT: 1358952 bytes 
    #IN: 2 kbps    OUT: 10 kbps
                                                    IN: 349998 bytes     OUT: 1359092 bytes 
    

    #! /bin/bash read -p "Enter your net port:[eth0|eth1|eth2]" ifcfg typeset in in_old dif_in dif_in1 dif_out1 typeset out out_old dif_out

    in_old=$(cat /proc/net/dev | grep $ifcfg | sed  's=^.*:==' | awk '{ print $1 }' ) out_old=$(cat /proc/net/dev | grep $ifcfg | sed  's=^.*:=='  | awk '{ print $9 }')

    while true do          sleep 1          in=$(cat /proc/net/dev | grep $ifcfg | sed  's=^.*:=='  | awk '{ print $1 }')          out=$(cat /proc/net/dev | grep $ifcfg | sed  's=^.*:=='  | awk '{ print $9 }')          dif_in=$((in-in_old))          dif_in1=$((dif_in * 8 / 1024 /1024 ))          dif_out=$((out-out_old))          echo "                                         IN: ${dif_in} bytes     OUT: ${dif_out} bytes "          dif_out1=$((dif_out * 8 / 1024 /1024 ))          echo "IN: ${dif_in1} mbps    OUT: ${dif_out1} mbps"          in_old=${in}          out_old=${out} done

    #运行效果: # ./stream.sh                                                 IN: 349179 bytes     OUT: 1363936 bytes #IN: 2 mbps    OUT: 10 mbps                                                 IN: 349612 bytes     OUT: 1361852 bytes #IN: 2 mbps    OUT: 10 mbps                                                 IN: 348684 bytes     OUT: 1358952 bytes #IN: 2 mbps    OUT: 10 mbps                                                 IN: 349998 bytes     OUT: 1359092 bytes

    展开全文
  • Linux中有很多的流量监控工具,它们可以监控、分类网络流量,以花哨的图形用户界面提供实时流量分析报告。大多数这些工具(例如:ntopng , iftop )都是基于libpcap 库的 ,这个函数库是用来截取流经网卡的...
    本文由 极客范 - 彭秦进 翻译自 Dan Nanni。欢迎加入极客翻译小组,同我们一道翻译与分享。转载请参见文章末尾处的要求。
    

    nethogs2

    在Linux中有很多的流量监控工具,它们可以监控、分类网络流量,以花哨的图形用户界面提供实时流量分析报告。大多数这些工具(例如:ntopng  iftop )都是基于libpcap 库的 ,这个函数库是用来截取流经网卡的数据包的,可在用户空间用来监视分析网络流量。尽管这些工具功能齐全,然而基于libpcap库的流量监控工具无法处理高速(Gb以上)的网络接口,原因是由于在用户空间做数据包截取的系统开销过高所致。

    在本文中我们介绍一种简单的Shell 脚本,它可以监控网络流量而且不依赖于缓慢的libpcap库。这些脚本支持Gb以上规模的高速网络接口,如果你对“汇聚型”的网络流量感兴趣的话,它们可统计每个网络接口上的流量。

    脚本主要是基于sysfs虚拟文件系统,这是由内核用来将设备或驱动相关的信息输出到用户空间的一种机制。网络接口的相关分析数据会通过“/sys/class/net/<ethX>/statistics”输出。

    举个例子,eth0的网口上分析报告会输出到这些文件中:

    • /sys/class/net/eth0/statistics/rx_packets: 收到的数据包数据
    • /sys/class/net/eth0/statistics/tx_packets: 传输的数据包数量
    • /sys/class/net/eth0/statistics/rx_bytes: 接收的字节数
    • /sys/class/net/eth0/statistics/tx_bytes: 传输的字节数
    • /sys/class/net/eth0/statistics/rx_dropped: 当收到包数据包下降的数据量
    • /sys/class/net/eth0/statistics/tx_dropped: 传输包数据包下降的数据量

    这些数据会根据内核数据发生变更的时候自动刷新。因此,你可以编写一系列的脚本进行分析并计算流量统计。下面就是这样的脚本(感谢 joemiller 提供)。第一个脚本是统计每秒数据量,包含接收(RX)或发送(TX)。而后面的则是一个描述网络传输中的接收(RX)发送(TX)带宽。这些脚本中安装不需要任何的工具。

    测量网口每秒数据包:

    网络带宽测量

    下面的屏幕截图显示了上面的两个脚本的输出。

    152940zdJ


    原连接:http://www.geekfan.net/5558/

    展开全文
  • Linux中有很多的流量监控工具,它们可以监控、分类网络流量,以花哨的图形用户界面提供实时流量分析报告。大多数这些工具(例如:ntopng , iftop )都是基于libpcap 库的 ,这个函数库是用来截取流经网卡的...

    在Linux中有很多的流量监控工具,它们可以监控、分类网络流量,以花哨的图形用户界面提供实时流量分析报告。大多数这些工具(例如:ntopng  iftop )都是基于libpcap 库的 ,这个函数库是用来截取流经网卡的数据包的,可在用户空间用来监视分析网络流量。尽管这些工具功能齐全,然而基于libpcap库的流量监控工具无法处理高速(Gb以上)的网络接口,原因是由于在用户空间做数据包截取的系统开销过高所致。

    在本文中我们介绍一种简单的Shell 脚本,它可以监控网络流量而且不依赖于缓慢的libpcap库。这些脚本支持Gb以上规模的高速网络接口,如果你对“汇聚型”的网络流量感兴趣的话,它们可统计每个网络接口上的流量。

    脚本主要是基于sysfs虚拟文件系统,这是由内核用来将设备或驱动相关的信息输出到用户空间的一种机制。网络接口的相关分析数据会通过“/sys/class/net/<ethX>/statistics”输出。

    举个例子,eth0的网口上分析报告会输出到这些文件中:

    • /sys/class/net/eth0/statistics/rx_packets: 收到的数据包数据
    • /sys/class/net/eth0/statistics/tx_packets: 传输的数据包数量
    • /sys/class/net/eth0/statistics/rx_bytes: 接收的字节数
    • /sys/class/net/eth0/statistics/tx_bytes: 传输的字节数
    • /sys/class/net/eth0/statistics/rx_dropped: 当收到包数据包下降的数据量
    • /sys/class/net/eth0/statistics/tx_dropped: 传输包数据包下降的数据量

    这些数据会根据内核数据发生变更的时候自动刷新。因此,你可以编写一系列的脚本进行分析并计算流量统计。下面就是这样的脚本(感谢 joemiller 提供)。第一个脚本是统计每秒数据量,包含接收(RX)或发送(TX)。而后面的则是一个描述网络传输中的接收(RX)发送(TX)带宽。这些脚本中安装不需要任何的工具。

    测量网口每秒数据包:

    网络带宽测量

    下面的屏幕截图显示了上面的两个脚本的输出。

    152940zdJ

    展开全文
  • 先上指令: 获取接收数据总字节数: ifconfig eth0 | grep 'byte' | sed 's/^.*RX[[:space:]]bytes://' | sed 's/[[:space:]].*$//' 获取发送数据总字节数: ifconfig eth0 | grep 'byte' | sed 's/^.*TX[[:...
  • Linux中有很多的流量监控工具,它们可以监控、分类网络流量,以花哨的图形用户界面提供实时流量分析报告。大多数这些工具(例如:ntopng , iftop )都是基于libpcap 库的 ,这个函数库是用来截取流经网卡的...
  • kail linux arp 欺骗 断网 流量转发

    千次阅读 2018-01-21 10:39:04
    arp攻击 工具:arpspoof 查看使用办法 arpspoof -h Usage: arpspoof [-i interface] [-c own|host|both] ...这个命令的用法是 让 目标ip的流量发到 当前机器的网卡,如果设置了ip_forward就会转发到网关,没有 就会断
  • # echo ${a:1:3} 从序号1开始截取3位 位置从0开始 bcd [root@desktop0 ~]# echo ${a:0:3} 从序号0开始截取3位 abc [root@desktop0 ~]# echo ${a::3} 0可以省略 abc [root@desktop0 ~]# echo $a | cut -b 1 截第1位 ...
  • tcpdump命令 – 监听网络流量 tcpdump命令是一款sniffer工具,是linux上的抓包工具,嗅探器;它可以打印出所有经过网络接口的数据包的头信息。 tcpdump命令工作时先要把网卡的工作模式切换到混杂模式。所以tcpdump...
  • 目标主机就不会断网,并且流量会经过我们的主机 既然目标流量会经过我们这里,那么开启一下drifient,便可捕获图片,我们新开一个终端,输入命令 打开指令 driftnet -i eth0 当目标主机浏览网页时就可以截取目标主机...
  • 获取Linux网络流量脚本 语法:[--help] [-i] [-d] #!/bin/bash VERSION="1.0.0.1" eth="" sec=0 help() { printf "Version: $VERSION \n\ Usage: $0 [-i interface] [-d time]\n\ \t-i|--interface...
  • linux sar查看网络流量

    千次阅读 2014-05-21 15:17:01
    Linux 2.6.32-220.el6.x86_64 (dwhtest) 05/21/2014 _x86_64_ (24 CPU) 03:41:25 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s 03:41:26 PM lo 3.96 3.96 0.23 0.23 0.00 0.00 0.00 03:41:...
  • Linux中有很多的流量监控工具,它们可以监控、分类网络流量,以花哨的图形用户界面提供实时流量分析报告。本文中我们介绍一种简单的Shell 脚本,它可以监控网络流量而且不依赖于缓慢的libpcap库。 AD:2013云计算...
  • 本文讲的是如何将Kali Linux秒变成一个能够拦截网络流量的代理路由器, 前言 这个存储库包含将Kali Linux设备转换成路由器的代码。Kali Linux变成路由器后可以实现两个功能: 1.记录所有与wireshark的流量,...
  • 因为本人是羸弱一枚,自身技术有很多不足,文章哪里写的有问题的希望各位大佬多多指正。 Orz Orz 为了演示,我还是使用两个系统,使用虚拟机的同一种网络链接模式,使两台虚拟机处于同一 ... Kali Linux下进行内...
  • #用sed先获取第7列,再用awk获取第2列,再cut切割,从第7个到最后,即只切割网卡流量数字部分 rx_after=$(cat /proc/net/dev | grep 'enp' | tr : " " | awk '{print $2}') tx_after=$(cat /proc/net/dev | grep 'enp'...
  • 它可以作为一个后台进程记录实时流量并输出到文件,由于具有轻型和灵活的特性,所以它可以很容易适应不同的应用程序。它不显示原始HTTP传输的数据,而是着重解析和显示相关数据字段的请求和响应行。 应用场景 ...
  • 网络流量分析利器-可视化网络-netflow【1】-基础原理 网络流量分析利器-可视化网络-netflow【2】-Cisco NetFlow 工作原理介绍及配置 ...网络流量分析利器-可视化网络-netflow【5】-linux下数据采集器f...
  • Linux中有很多的流量监控工具,它们可以监控、分类网络流量,以花哨的图形用户界面提供实时流量分析报告。大多数这些工具(例如:ntopng , iftop )都是基于libpcap 库的 ,这个函数库是用来截取流经网卡的数据包的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,516
精华内容 2,206
关键字:

linux流量截取

linux 订阅