ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

采用Jpcap+redis+线程 网络流量监控

2019-03-31 10:53:26  阅读:331  来源: 互联网

标签:String redis 网络流量 infoMap 线程 nICEntity put import jpcap


转载请注明出处:https://www.cnblogs.com/sun-flower1314/p/10630424.html

一、问题场景:目前需要服务器端去监控部署在各个城市的设备(包括终端、大屏互动设备、广告机等)的流量情况,包括每台设备对服务器端发出字节数、发出数据包数、最大数据包、IP地址等数据,而设备对其他的服务的访问不予监控。

二、目前主要采用的技术组合是Jpcap+redis+线程的方式,实现思路是:不断的从网络中抓取对应设备对服务器请求的包数据,对包进行分析,然后将数据放入redis缓存中,每抓到对应的设备的数据就会刷新在缓存中的对应设备的数据。从而实现监控。注:用hash结构存储, 存入缓存中的是以设备ip为key,用map值作为value,取数据直接根据设备ip就能拿到对应的数据

三、首先是搭建redis服务(我是直接在虚拟机中搭建了一个redis作为开发测试),关于搭建redis服务,请网上自行百度

然后是下载jpcap所使用的jar包即jpcap需要的环境:

jpcap所需要的用到的文件为:jpcap.jar  Jpcap.dll 安装环境:WinPcap_4_1_2.exe注:这三个文件版本需要一致,如若网上找不到,可私聊我,我发给你)

1.将jpcap.jar拷贝jdk的lib\ext目录下(本人的为:JRE1.8\lib\ext),或者拷贝至项目中,然后Add to Build Path 到项目中;

2.将Jpcap.dll拷贝至自己的jdk的bin(本人的为:JRE1.8\bin)的目录下

3.双击安装WinPcap_4_1_2.exe,若未安装这个,则没有相应的环境,后面一直会报错: java.lang.UnsatisfiedLinkError: D:\JRE1.8\bin\Jpcap.dll: Can't find dependent libraries即:

 4.以下为实现代码,代码部分较多,会贴主要的,(部分工具类和初始化未贴出)代码上也有相应注释。需要完整的源码,请私聊我,我发给你。

完整的包结构:

 配置文件部分:

然后是实现代码:

动态传入过滤条件,再启动一个线程去跑

package com.hxc.hwkj.jpcapcatch.impl;

import java.util.logging.Logger;

import com.hxc.hwkj.core.CatchDataStart;
import com.hxc.hwkj.entity.NetworkInterfaceEntity;
import com.hxc.hwkj.jpcapcatch.CatchDataMonitorStart;
import com.hxc.hwkj.util.LocalWinInfoUtils;

import jpcap.JpcapCaptor;
import jpcap.NetworkInterface;
import jpcap.NetworkInterfaceAddress;

/**
 * @Description 设备接口信息
 * 2019年3月26日  下午3:53:01
 * @Author Huangxiaocong
 */
public class CatchDataMonitorStartImpl implements CatchDataMonitorStart {
    private static Logger log = Logger.getLogger(CatchDataMonitorStartImpl.class.toString());
    /**
     * 通过过滤条件去抓取数据
     * @param cond 设置过滤的条件(包括设备的ip地址,但不仅限于此)
     * @Author Huangxiaocong 2019年3月26日 下午3:40:25
     */
    public void catchDataByConditon(String cond) {
        NetworkInterface[] devices = JpcapCaptor.getDeviceList();
        NetworkInterfaceEntity nICEntity = null;
        for(int i = 0; i < devices.length; i++) {
            NetworkInterface netInterface = devices[i];
            nICEntity = getServerDeciverInfo(netInterface);
            String ipv4 = nICEntity.getIpv4Addr();
            String mac = nICEntity.getMacAddr().replace(':', '-');
            //与当前网卡比较mac地址和ipv4地址
            if(LocalWinInfoUtils.getIpAddress().equals(ipv4) //
                    && LocalWinInfoUtils.getMacAddress().equalsIgnoreCase(mac)) {
                //生成情况  服务器端作为dst 目标  客户端作为源src
                String filterCond = cond == null || cond.equals("") ? "( dst host " + ipv4 + ")" : cond + " and ( dst host " + ipv4 + ")";
                //log.info("过滤条件为:" + filterCond);
                startCapThread(netInterface, filterCond);
            } else {
                continue;
            }
            System.out.println("设备信息为:" + nICEntity);
        }
    }
    
    /**
     * 启动一个线程独立运行抓包
     * @param deviceName
     * @param condition
     * @Author Huangxiaocong 2019年3月26日 下午2:35:51
     */
    public void startCapThread(NetworkInterface deviceName, String filterCond) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                log.info("启动对 " + deviceName + "抓包线程");
                CatchDataStart catchDataStart = new CatchDataStart();
                catchDataStart.init(deviceName, filterCond);
            }
        };
        new Thread(runnable).start();
    }
    
    /**
     * 获取网卡的信息
     * @param netInterface 
     * @return
     * @Author Huangxiaocong 2019年3月26日 下午2:22:36
     */
    public NetworkInterfaceEntity getServerDeciverInfo(NetworkInterface netInterface) {
        NetworkInterfaceEntity nICEntity = new NetworkInterfaceEntity();
        nICEntity.setNICName(netInterface.name);
        nICEntity.setNICDesc(netInterface.description);
        nICEntity.setDataLinkName(netInterface.datalink_name);
        nICEntity.setDataLinkDesc(netInterface.datalink_description);
        //计算mac地址
        byte[] bs = netInterface.mac_address;
        StringBuilder sBuilder = new StringBuilder();
        int count = 1;
        for(byte b : bs) {
            sBuilder.append(Integer.toHexString(b & 0xff));
            if(count++ != bs.length) sBuilder.append(":");
        }
        nICEntity.setMacAddr(sBuilder.toString());
        //查找ip地址
        NetworkInterfaceAddress[] netInterAddresses = netInterface.addresses;
        for(int i = 0; i < netInterAddresses.length; i++) {
            if(i == 0) {
                nICEntity.setIpv6Addr(netInterAddresses[i].address.getHostAddress());
            } else if(i == 1) {
                nICEntity.setIpv4Addr(netInterAddresses[i].address.getHostAddress());
                nICEntity.setBroadcase(netInterAddresses[i].broadcast.getHostAddress());
                nICEntity.setSubnet(netInterAddresses[i].subnet.getHostAddress());
            }
        }
        return nICEntity;
    }
}

 

 

package com.hxc.hwkj.core;

import java.io.IOException;
import java.util.logging.Logger;

import com.hxc.hwkj.init.InitJpcat;
import com.hxc.hwkj.jpcapcatch.impl.CatchDataPacketInfo;

import jpcap.JpcapCaptor;
import jpcap.NetworkInterface;

public class CatchDataStart {
    private static Logger log = Logger.getLogger(CatchDataStart.class.toString());
    /**
     * 初始化参数信息 取得在指定网卡上的Jpcapcator对象
     * @param deviceName 网卡名称
     * @param filterCond 过滤条件
     * @Author Huangxiaocong 2019年3月26日 下午2:47:53
     */
    public void init(NetworkInterface deviceName, String filterCond) {
        JpcapCaptor jpcap = null;
        try {
            jpcap = JpcapCaptor.openDevice(deviceName, InitJpcat.snaplen, InitJpcat.promisc, InitJpcat.to_ms);
            //过滤代码 可以是协议 端口 IP 组合
            if(filterCond != null && !"".equals(filterCond)) {
                jpcap.setFilter(filterCond, true);
            }
        } catch (IOException e) {
            log.info("打开一个网卡失败" + e);
        }
        jpcap.loopPacket(InitJpcat.loopCount, new CatchDataPacketInfo(jpcap));
    }
}

 

下面这部分是对包的解析,包括各种协议: 

package com.hxc.hwkj.jpcapcatch.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import com.hxc.hwkj.jpcapcatch.CatchDataToCache;

import jpcap.JpcapCaptor;
import jpcap.PacketReceiver;
import jpcap.packet.ARPPacket;
import jpcap.packet.EthernetPacket;
import jpcap.packet.ICMPPacket;
import jpcap.packet.Packet;
import jpcap.packet.TCPPacket;
import jpcap.packet.UDPPacket;
/**
 * @Description 抓包获取数据并分析信息  
 * 2019年3月26日  下午2:42:12
 * @Author Huangxiaocong
 */
public class CatchDataPacketInfo implements PacketReceiver {
    private static Logger log = Logger.getLogger(CatchDataPacketInfo.class.toString());
    
    private JpcapCaptor jpcap = null;
    public CatchDataPacketInfo(JpcapCaptor jpcap) {
        this.jpcap = jpcap;
    }
    
    /**
     * 解析包信息
     */
    @Override
    public void receivePacket(Packet packet) {
        //封装抓包获取数据
        Map<String, String> infoMap = new HashMap<>();
        //分析协议类型
        if(packet instanceof ARPPacket) { //该协议无端口号
            ARPPacket arpPacket = (ARPPacket) packet;
            infoMap.put("ContractType", "ARP协议");
            infoMap.put("Caplen", String.valueOf(arpPacket.caplen));
            infoMap.put("SecTime", String.valueOf(arpPacket.sec));
            infoMap.put("SourceIp", arpPacket.getSenderProtocolAddress().toString().replace("/", ""));
            infoMap.put("SourceMacAddr", arpPacket.getSenderHardwareAddress().toString());
            infoMap.put("TargetIp", arpPacket.getTargetProtocolAddress().toString().replace("/", ""));
            infoMap.put("TargetMacAddr", arpPacket.getTargetHardwareAddress().toString());
        } else if(packet instanceof UDPPacket) {
            UDPPacket udpPacket = (UDPPacket) packet;
            EthernetPacket datalink = (EthernetPacket) udpPacket.datalink;
            infoMap.put("ContractType", "UDP协议");
            infoMap.put("Caplen", String.valueOf(udpPacket.caplen));
            infoMap.put("SecTime", String.valueOf(udpPacket.sec));
            infoMap.put("SourceIp", udpPacket.src_ip.getHostAddress());
            infoMap.put("SourcePort", String.valueOf(udpPacket.src_port));
            
            infoMap.put("SourceMacAddr", getMacInfo(datalink.src_mac));
            infoMap.put("TargetIp", udpPacket.dst_ip.getHostAddress());
            infoMap.put("TargetPort", String.valueOf(udpPacket.dst_port));
            infoMap.put("TargetMacAddr", getMacInfo(datalink.dst_mac));
        } else if(packet instanceof TCPPacket) {
            TCPPacket tcpPacket = (TCPPacket) packet;
            EthernetPacket datalink = (EthernetPacket) tcpPacket.datalink;
            infoMap.put("ContractType", "TCP协议");
            infoMap.put("Caplen", String.valueOf(tcpPacket.caplen));
            infoMap.put("SecTime", String.valueOf(tcpPacket.sec));
            infoMap.put("SourceIp", tcpPacket.src_ip.getHostAddress());
            infoMap.put("SourcePort", String.valueOf(tcpPacket.src_port));
            
            infoMap.put("SourceMacAddr", getMacInfo(datalink.src_mac));
            infoMap.put("TargetIp", tcpPacket.dst_ip.getHostAddress());
            infoMap.put("TargetPort", String.valueOf(tcpPacket.dst_port));
            infoMap.put("TargetMacAddr", getMacInfo(datalink.dst_mac));
        } else if(packet instanceof ICMPPacket) { //该协议无端口号
            ICMPPacket icmpPacket = (ICMPPacket) packet;
            EthernetPacket datalink = (EthernetPacket) icmpPacket.datalink;
            infoMap.put("ContractType", "ICMP协议");
            infoMap.put("Caplen", String.valueOf(icmpPacket.caplen));
            infoMap.put("SecTime", String.valueOf(icmpPacket.sec));
            infoMap.put("SourceIp", icmpPacket.src_ip.getHostAddress());
            
            infoMap.put("SourceMacAddr", getMacInfo(datalink.src_mac));
            infoMap.put("TargetIp", icmpPacket.dst_ip.getHostAddress());
            infoMap.put("TargetMacAddr", getMacInfo(datalink.dst_mac));
        }
        try {
            CatchDataToCache catchDataToCache = new CatchDataToCacheImpl();
            catchDataToCache.setInfoToCache(infoMap);
        } catch (Exception e) {
            log.info("抓取数据装入缓存时 出现异常,请检查:" + e);
            jpcap.breakLoop();
            if(jpcap != null) {
                jpcap.close();
            }
        }
        
    }
    /**
     * 获取Mac信息
     * @param macByte
     * @return
     * @Author Huangxiaocong 2019年3月24日 下午3:19:30
     */
    protected String getMacInfo(byte[] macByte) {
        StringBuffer srcMacStr = new StringBuffer(); 
        int count = 1;
        for (byte b : macByte) {  
            srcMacStr.append(Integer.toHexString(b & 0xff));
            if(count++ != macByte.length) 
                srcMacStr.append(":");
        }
        return srcMacStr.toString();
    }
}

 

 下面部分代码是将数据存入redis中,有些数据是根据需要进行覆盖或者叠加:

package com.hxc.hwkj.jpcapcatch.impl;

import java.util.Map;

import com.hxc.hwkj.jpcapcatch.CatchDataToCache;
import com.hxc.hwkj.util.JedisPoolUtils;
import redis.clients.jedis.Jedis;

/**
 * @Description 将抓取到的数据装入缓存中 
 * 2019年3月27日  下午4:52:50
 * @Author Huangxiaocong
 */
public class CatchDataToCacheImpl implements CatchDataToCache {
    /**
     * 将数据存入redis缓存中
     * @param infoMap
     * @Author Huangxiaocong 2019年3月26日 下午4:24:07
     */
    public void setInfoToCache(Map<String, String> infoMap) throws Exception {
        if(infoMap.isEmpty()) {
            return ;
        }
        String deviceIp = infoMap.get("SourceIp");
        if(deviceIp == null || deviceIp.equals("")) {
            return ;
        }
        Jedis jedis = null;
        jedis = JedisPoolUtils.getJedis();
        //处理数据,找出最大的包
        String caplen = jedis.hget(deviceIp, "MaxCaplen");
        if(caplen == null || caplen.equals("")) {
            caplen = "0";
        }
        int nowCaplen = Integer.parseInt(infoMap.get("Caplen"));
        if(Integer.parseInt(caplen) < nowCaplen) {
            infoMap.put("MaxCaplen", String.valueOf(nowCaplen));
        } else {
            infoMap.put("MaxCaplen", caplen);
        }
        jedis.hmset(deviceIp, infoMap);
        //发包次数
        jedis.hincrBy(deviceIp, "counttimes", 1);
        //生产现场需要删除
        /*Map<String, String> tempMap = jedis.hgetAll(deviceIp);
        Set<Entry<String, String>> entry = tempMap.entrySet();
        for(Entry<String, String> en : entry ) {
            System.out.println(en.getKey() + " --- > " + en.getValue());
        }*/
        JedisPoolUtils.closeJedisResource(jedis);
    }
}

 

 

以上就是实现,若有任何疑问,可留言,欢迎提出宝贵的意见。谢谢!!

转载请注明出处:https://www.cnblogs.com/sun-flower1314/p/10630424.html

 

标签:String,redis,网络流量,infoMap,线程,nICEntity,put,import,jpcap
来源: https://www.cnblogs.com/sun-flower1314/p/10630424.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有