采用Jpcap+redis+线程 设备网络流量监控 应用实战实例
.personSunflowerP { background: rgba(51, 153, 0, 0.66); border-bottom: 1px solid rgba(0, 102, 0, 1); border-top-left-radius: 7px; border-top-right-radius: 7px; color: rgba(255, 255, 255, 1); height: 1.8em; line-height: 1.8em; padding: 5px }
转载请注明出处:https://www.cnblogs.com/sun-flower1314/p/10630424.html
一、问题场景:
目前需要服务器端去监控部署在各个城市的设备(包括终端、大屏互动设备、广告机等)的流量情况,包括每台设备对服务器端发出字节数、发出数据包数、最大数据包、IP地址等数据,而设备对其他的服务的访问不予监控。
二、目前主要采用的技术组合是Jpcap+redis+线程的方式,
实现思路是:不断的从网络中抓取对应设备对服务器请求的包数据,对包进行分析,然后将数据放入redis缓存中(若需要数据需要可定时存入数据库进行记录),每抓到对应的设备的数据就会刷新在缓存中的对应设备的数据。从而实现监控。注:用hash结构存储, 存入缓存中的是以设备ip为key,用map值作为value,取数据直接根据设备ip就能拿到对应的数据
三、功能实现
环境的搭建
1. redis服务的搭建
(我是直接在虚拟机中搭建了一个redis作为开发测试),关于搭建redis服务,请网上自行百度
2.底层抓包环境的配置
下载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;
}
}
上面代码中的 getDeviceList表示可以获取机器上网络接口卡对象的数组,数组中的每个NetworkInterface代表一个网络接口。
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));
}
}
上面代码中关于openDevice方法和loopPacket方法的解释:
①openDevice(NetworkInterface intrface, int snaplen, boolean promisc, int to_ms)
取得在指定网卡上的Jpcapcator对象,Interface:所返回的某个网卡对象snaplen;snaplen:一次性要抓取数据包的最大长度
promisc:设置是否混杂模式,处于混杂模式将接收所有数据包,如果设置为混杂模式后,调用了包过滤函数setFilter()将不起任何作用;
to_ms : 这个参数主要用于processPacket()方法,指定超时的时间。
②int loopPacket(int count, PacketReceiver handler) :通过openDevice方法取得每个网络接口上的JpcapCaptor对象,就可通过这个方法抓包了。
count:表示要抓的包的数目,如果设置为-1表示永远抓下去;handler:第二个参数必须是实现了PacketReceiver接口的一个对象,抓到的包将调用这个对象的
receivePacket方法处理,这个方法调用会阻塞等待 与该方法相对应的是breakLoop(),在JacapCaptor对象上的阻塞等待的方法将强制终止
下面这部分是对包的解析,包括各种协议:
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);
}
}
测试部分,只需传入过滤条件就行:
package com.hxc.hwkj.test; import com.hxc.hwkj.jpcapcatch.CatchDataMonitorStart;
import com.hxc.hwkj.jpcapcatch.impl.CatchDataMonitorStartImpl; public class MainTest {
public static void main(String[] args) {
CatchDataMonitorStart deciveMonitorStart = new CatchDataMonitorStartImpl();
String cond = "src host 192.168.1.111";
deciveMonitorStart.catchDataByConditon(cond);
}
}
注:jpcap的过滤条件规则:
如:src host 192.168.1.111 表示过滤源主机地址为192.168.1.111的数据
1.dst host xx.xx.xx.xx 过滤目标主机ip为 xx.xx.xx.xx的数据
2.host xx.xx.xx.xx 过滤目标或源主机为xx.xx.xx.xx的数据
3.src port xx 过滤源端口号为xx的数据
4.http or telnet 过滤http或telnet协议的数据
等等...
其条件可以组合使用:
取反操作 (`!' 或 `not').
连接操作 (`&&' 或 `and').
选择操作 (`||' 或 `or').
这里列出的为常用的过滤表达式,关于更多的过滤条件请百度
以上就是实现,若有任何疑问或需要,可留言,欢迎点赞评论,谢谢你的鼓励!!
转载请注明出处:https://www.cnblogs.com/sun-flower1314/p/10630424.html
采用Jpcap+redis+线程 设备网络流量监控 应用实战实例的更多相关文章
- Linux网络流量监控与分析工具Ntopng
Ntopng工具 Ntopng是一个功能强大的流量监控.端口监控.服务监控管理系统 能够实现高效地监控多台服务器网络 Ntopng功能介绍 Ntop提供了命令行界面和web界面两种工作方式,通过web ...
- 搭建一个简单的基于web的网络流量监控可视化系统
本文转载于我的个人博客,转载请标明出处. 初衷 在腾讯云的学生认证申请提交上去n天之后,终于得到了审批,所以迫不及待的想玩玩腾讯云,作为一个搞网络的,自然有一些关于网络应用的小玩意,所以把以前部署过的 ...
- linux系统CPU,内存,磁盘,网络流量监控脚本
前序 1,#cat /proc/stat/ 信息包含了所有CPU活动的信息,该文件中的所有值都是从系统启动开始累积到当前时刻 2,#vmstat –s 或者#vmstat 虚拟内存统计 3, #cat ...
- linux 网络数据收发网络流量监控
网卡流量 1.iftop命令 iftop可以用来监控网卡的实时流量(可以指定网段).反向解析IP.显示端口信息.TCP/IP连接等官网:http://www.ex-parrot.com/~pdw/if ...
- CentOS 6.4 搭建 ntop 网络流量监控分析平台
[前言] Ntop是一种监控网络流量工具,用ntop显示网络的使用情况比其他一些网络管理软件更加直观.详细.Ntop甚至可以列出每个节点计算机的网络带宽利用率. 功能: 自动从网络中识别有用的信息: ...
- Zabbix配置网络流量监控报警
一.SNMP简单概述 1.什么是Snmp SNMP是英文"Simple Network Management Protocol"的缩写,中文意思是"简单网络管理协议&qu ...
- 网络流量监控分析工具 Ntopng 安装
官方说明:http://packages.ntop.org/ http://packages.ntop.org/centos-stable/ http://packages.ntop.o ...
- 网络流量监控shell脚本
网络收发包计数记录在 /proc/net/dev 文件中, 要取得流量, 只需要读取里面的内容两次, 然后相减, 再除以时间间隔即可. #!/bin/bash #Usage1,record in fi ...
- 使用iftop网络流量监控
iftop这是一个非常有用的工具.下面的命令监视无线网卡在我的笔记本 iftop -i wlan0 比如,我现在玩音乐视频.iftop显示的信息: 基本说明: 1. 屏幕主要部分都是表示两个机器之间的 ...
随机推荐
- 7、Oracle通过客户端(sqlplus)登录认证用户的方式
select version from v$instance; #查看当前数据库的版本 192.168.31.5:1521/orcl 7.1.操作系统认证: 1.Oracle认为操作系统用户是可靠的, ...
- 『无为则无心』Python函数 — 25、Python中的函数
目录 1.函数的使用 (1)定义函数 (2)调用函数 (3)使用函数的注意事项 2.函数的参数 3.实参的类型 Python函数的说明: Python中函数的应用非常广泛,前面章节中我们已经接触过多个 ...
- 初入web前端---实习(职场菜鹏)
作为一个大四的准职场新人,顺利的找到了一份自己想从事的工作---web前端开发.
- 万字长文肝Git--全流程知识点包您满意【建议收藏】
您好,我是码农飞哥,感谢您阅读本文,欢迎一键三连哦. 本文将首先介绍在本地搭建GitLab服务,然后重点介绍Git的常用命令,Git的核心概念以及冲突处理,最后介绍Git与SVN的区别 干货满满,建议 ...
- ESP32 ADF windows开发环境搭建 适配ADF到ESP32A1S(转)
搭建ESP32A1S的ADF开发环境 一,获取IDF和IDF-TOOL adf是乐鑫的音频开发框架,里面有许多乐鑫的音频开发API,同时ADF是基于IDF的.这一部分可以按照官网的教程一步一步来.官网 ...
- Http2.0详解
前言 HTTP/1.1协议为现在网络提供了20年的支持.从那时起,网站已经从静态的.文本驱动的文档发展为交互式的.富媒体的应用程序.在此期间底层协议保持不变这一事实正好说明了它的通用性和能力.但随着网 ...
- python使用笔记008-模块
模块的原理: 1.就是一个python文件 2.标准模块是python自带的 3.第三方模块需要自己安装 导入模块的顺序: 1.从当前目录下找 2.从python的环境变量中找 一.自己定义的模块 1 ...
- Java 批量删除Word中的空白段落
1. 测试文档.期望达到的目标文档效果 用于测试的Word文档如下所示,包含的空白段落影响文章整体布局及美观性: 目标文档效果: 2. 辅助工具 2.1 使用类库:Free Spire.Doc for ...
- 【Mysql】InnoDB 中的聚簇索引、二级索引、联合索引
接上一篇内容. 一.聚簇索引 其实之前内容中介绍的 B+ 树就是聚簇索引. 这种索引不需要我们显示地使用 INDEX 语句去创建,InnoDB 引擎会自动创建.另外,在 InnoDB 引擎中,聚簇索引 ...
- Git的使用(六)
前言 版本管理工具总结: 开发团队项目,对项目的版本进行管理. 使用过的版本管理工具: TFS.SVN与Git. TFS:管理项目,通过visual Studio管理源码,拉取分支,提交代码等.也可以 ...