ToB企服应用市场:ToB评测及商务社交产业平台

标题: Java + Jpcap实现监控 IP包流量 [打印本页]

作者: 十念    时间: 2023-4-14 23:05
标题: Java + Jpcap实现监控 IP包流量
Java + Jpcap实现监控 IP包流量

说明:本设计是计算机网络课程的课设,因为代码是提前实现的,本博客于后期补上,又因为代码没写注释自己也看不懂了,所以,仅供参考,就当提供一种实现方式。
文中提供的《Jpcap中文API文档》来源于网络,本文仅用于学习交流,如有侵权,可联系我进行删除。
效果图:

1)课程设计要求

1.1 课程设计目的

通过本实课程设计,有助于理解 IP包的格式和加深对 IP 协议的理解。
1.2 课程设计要求

编制程序,监控网络,捕获一段时间内网络上的 IP 数据包,按 IP 数据包的源地址统计出该源地址在该时间段内发出的 IP 包的个数,将其写人日志文件中或用图形表示出来(建议用图形表示出统计结果)。
1.3 程序的具体要求如下

用命令行运行: IPStatistic time logfile
其中, IPStatistic 是程序名; time 是设定的统计时间间隔(单位为分钟,比如,2表示2分钟);  logfile 表示统计结果写人的日志文件名(若用图形表示统计结果则可以不选这个参数)。
2)编码前的准备

2.1 技术点

后端:springboot,Jpcap
前端:vue2,ECharts
说明:Jpcap是一个能够捕获、发送网络数据包的java类库包。
2.2 环境搭建

2.2.1 事先说明和下载链接

ps:网上大部分都是Jpcap+winpcap,但是winpcap太老了,大概率在Windows10和Windows11上会出问题,当时也踩了不少坑,这里推荐使用npcap
winocap网址:https://www.winpcap.org/
Npcap网址:https://npcap.com/
从图中可以看出,winocap已经不再支持,推荐使用npcap

进入Npcap官网下载即可

2.2.2 资源下载

链接:https://pan.baidu.com/s/1y6u-V-FPwOgIxC9ZoAD7yg
提取码:1111
内容:
2.2.3安装

重点1、3、4步

3)编码

重要提示:当时为了赶工,其中的逻辑很有问题,现在的评价就一个字,烂,非常烂!!!看看关键实现就行。
这里推荐看这篇博客,写的很好,里面对重要字段进行了说明:https://www.cnblogs.com/shy-huiying/p/5636274.html
3.1 后端实现

3.1.1 获得本机所有网卡接口信息

Jpcap提供了方法JpcapCaptor.getDeviceList()完成这个任务,该方法返回一组NetworkInterface对象。
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
  1. /**
  2. *  这里是controller层
  3. * 获得所有网卡接口
  4. * @return List<String>
  5. */
  6. @RequestMapping("/info")
  7. public Object getNetworkCard(){
  8.     // 获取网络接口列表,返回所有的网络设备数组;
  9.     NetworkInterface[] devices = JpcapCaptor.getDeviceList();
  10.     if (devices.length == 0) {
  11.         return "无网卡信息";
  12.     }else{
  13.         List<NetworkCardPojo> netList = new ArrayList<>();
  14.         int index = 0;
  15.         for (NetworkInterface n : devices) {
  16.             //NetworkCardPojo是自己编写的实体类,包含网卡接口索引和网卡接口名两个属性
  17.             NetworkCardPojo networkCardPojo = new NetworkCardPojo();
  18.             networkCardPojo.setIndex(index++);
  19.             networkCardPojo.setDescription(n.description);
  20.             //networkCardPojo.setNetworkInterface(n);
  21.             netList.add(networkCardPojo);
  22.         }
  23.         return netList;
  24.     }
  25. }
复制代码
  1. public class NetworkCardPojo {
  2.     private Integer index;
  3.     private String description;
  4.     //private NetworkInterface NetworkInterface;
  5. }
复制代码
返回到前端的数据:

3.1.2 得到指定网卡的具体信息

  1.    /**
  2.             *  这里是controller层
  3.      *  打印选择网卡的IP地址和子网掩码;
  4.      * @param index
  5.      * @return
  6.      */
  7.     @RequestMapping("/local")
  8.     public LocalParameterPojo getLocalParameter(@ProbeParam("index") Integer index){       
  9.         NetworkInterface[] devices = JpcapCaptor.getDeviceList();
  10.         //根据传入的网卡索引获取该网卡接口所属的IP地址
  11.         NetworkInterfaceAddress[] device = devices[index].addresses;
  12.         //LocalParameterPojo是自己编写的实体类,包含本机IP地址、子网掩码、网络连接类型
  13.         LocalParameterPojo local = new LocalParameterPojo();
  14.         if (device.length>0){
  15.             local.setIpv4(device[0].address);
  16.             local.setSubnetMask(device[0].subnet);
  17.             local.setNetType(devices[0].datalink_description);
  18.         }else {
  19.             local.setNetType("该网卡接口不可用,请尝试切换其他网卡接口!");
  20.         }
  21.         return local;
  22.     }
复制代码
LocalParameterPojo实体类,注意部分字段是InetAddress类型
  1. public class LocalParameterPojo {
  2.     private InetAddress ipv4;            //本机IP地址
  3.     private InetAddress SubnetMask;      //子网掩码
  4.     private String netType;         //网络连接类型
  5. }
复制代码

3.1.3 监控ip包数据

因为一个ip地址会发送多个ip包,这里主要是将ip包进行分组统计:
IP地址--累计IP包数量--累计IP包大小
这里写的不好,有些问题,甚至问题很大,后面想到有更好的解决方法,但是没有尝试过,就不写了
  1.     /**
  2.      * 这里是controller层
  3.      * 开启监控ip包流量监控
  4.      * @param index
  5.      * @return
  6.      */
  7.     @RequestMapping("/start")
  8.     public List<TargetParameterPojo> startGetPacket(@ProbeParam("index") Integer index){
  9.         targetParameter.startThread(index);
  10.         //根据Ip地址分组
  11.         Map<InetAddress, IpGroup> mapAll = new HashMap<>();
  12.         System.out.println("ip count:"+targetParameter.getTargetMap().size());
  13.         for (int i=0;i<targetParameter.getTargetMap().size();i++){
  14.             IpGroup ipGroup = new IpGroup();
  15.             for (InetAddress key:targetParameter.getTargetMap().get(i).keySet()){
  16.                 Integer size = targetParameter.getTargetMap().get(i).get(key);
  17.                 int count=1;
  18.                 //检查 hashMap 中是否存在指定的 key 对应的映射关系。
  19.                 if(mapAll.containsKey(key)){
  20.                     Integer tempSize = mapAll.get(key).getSize();
  21.                     size += tempSize;
  22.                     Integer tempCount = mapAll.get(key).getCount();
  23.                     count += tempCount;
  24.                 }
  25.                 ipGroup.setCount(count);
  26.                 ipGroup.setSize(size);
  27.                 mapAll.put(key,ipGroup);
  28.             }
  29.         }
  30.         // 将数据装到TargetParameterPojo
  31.         List<TargetParameterPojo> targetList = new ArrayList<>();
  32.         for (Map.Entry<InetAddress,IpGroup> map:mapAll.entrySet()){
  33.             TargetParameterPojo targetPojo = new TargetParameterPojo();
  34.             targetPojo.setSourceIp(map.getKey());
  35.             targetPojo.setSize(map.getValue().getSize());
  36.             targetPojo.setCount(map.getValue().getCount());
  37.             targetList.add(targetPojo);
  38.         }
  39.         return targetList;
  40.     }
  41.     /**
  42.      * 关闭监控ip包流量
  43.      * @return
  44.      */
  45.     @RequestMapping("/stop")
  46.     public int stopsGetPacket(){
  47.         int flag = targetParameter.getTargetMap().size();
  48.         if(flag>1){
  49.             targetParameter.stopThread();
  50.             return 1;
  51.         }else {
  52.             return 0;
  53.         }
  54.     }
复制代码
service层
  1. @Service
  2. public class TargetParameter implements Runnable{
  3.     //数据统计要用到的list
  4.     private static List<Map<InetAddress,Integer>> targetMap = new ArrayList<>();
  5.     private boolean flag = true;
  6.     private TargetParameter tp;
  7.     private Thread thread;
  8.     private Integer isOff=0;
  9.     public TargetParameter(JpcapCaptor jpcap) {
  10.         this.jpcap = jpcap;
  11.     }
  12.     private JpcapCaptor jpcap = null;
  13.     public TargetParameter() {
  14.     }
  15.     public List<Map<InetAddress, Integer>> getTargetMap() {
  16.         return targetMap;
  17.     }
  18.     @Override
  19.     public void run() {
  20.         //只要不停止就一直进行抓包
  21.         while (flag){
  22.             IPPacket ipPacket = (IPPacket) jpcap.getPacket();
  23.             if (ipPacket!=null){
  24.                 Map<InetAddress,Integer> map = new HashMap<>();
  25.                 map.put(ipPacket.src_ip,ipPacket.len);
  26.                 targetMap.add(map);
  27.             }
  28.             // 回调方法
  29.             //jpcap.processPacket(-1, new CallbackService());
  30.         }
  31.     }
  32.     /**
  33.      * 开启线程方法
  34.      */
  35.     public void startThread(Integer index){
  36.         if (isOff==0){
  37.             try {
  38.                 NetworkInterface[] devices = JpcapCaptor.getDeviceList();
  39.                 //获得了JpcapCaptor实例就可以用来捕获来自网络接口的数据包。
  40.                 //网卡索引,捕获数据包大小,是否开启混杂模式(混杂模式会捕获到数据表),超时
  41.                 jpcap = JpcapCaptor.openDevice(devices[index], 1024, true, 1000);
  42.                 // 在捕获前先设置过滤;
  43.                 jpcap.setFilter("ip", true);
  44.             } catch (IOException e) {
  45.                 e.printStackTrace();
  46.                 System.out.println("抓取数据包时出现异常!!");
  47.             }
  48.             tp = new TargetParameter(jpcap);
  49.             //创建一个抓抓包线程,保证一直进行抓包
  50.             thread = new Thread(tp);
  51.             thread.start();
  52.             System.out.println("thread.getName():"+thread.getName());
  53.             isOff++;
  54.         }
  55.     }
  56.     /**
  57.      * 关闭线程并清空List
  58.      */
  59.     public void stopThread(){
  60.         isOff=0;
  61.         tp.flag=false;
  62.         targetMap.clear();
  63.         System.out.println(targetMap);
  64.     }
  65. }
复制代码
Pojo:
  1. public class TargetParameterPojo {
  2.     private InetAddress sourceIp;
  3.     private Integer count;
  4.     private Integer size;
  5. }
复制代码
  1. public class IpGroup {
  2.     private Integer size;
  3.     private Integer count;
  4. }
复制代码

3.1.4 目录结构


3.2 前端实现

前端实现很简单,主要是数据渲染,这里说一下我的思路:
4)END

资源下载
链接:https://pan.baidu.com/s/1y6u-V-FPwOgIxC9ZoAD7yg
提取码:1111
内容:
重要:请勿学习如上代码的写法,那时候vue正在学,还行学完,代码冗余严重。
本博客仅仅提供解决方法!欢迎讨论,感谢批评指正。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4