Java + Jpcap實現監控 IP包流量 說明:本設計是電腦網路課程的課設,因為代碼是提前實現的,本博客於後期補上,又因為代碼沒寫註釋自己也看不懂了,所以,僅供參考,就當提供一種實現方式。 文中提供的《Jpcap中文API文檔》來源於網路,本文僅用於學習交流,如有侵權,可聯繫我進行刪除。 效果 ...
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
內容:
- Jpcap中文API文檔
- npcap-1.72.exe
- Jpcap.dll
- jpcap.jar
- network_vue(前端代碼,需要自己裝包:
npm install
) - network_course_design(Java代碼)
2.2.3安裝
重點1、3、4步
-
Npcap.exe正常進行安裝即可
-
創建一個普通springboot項目
-
在項目中導入
Jpcap.jar
包
-
將
Jpcap.dll
放到JDK安裝路徑下的 /jre/bin 目錄下(我這裡好像沒有放也可以運行,可以試一下) -
前端就是一個普普通通的VUE+ECharts項目
3)編碼
重要提示:當時為了趕工,其中的邏輯很有問題,現在的評價就一個字,爛,非常爛!!!看看關鍵實現就行。
這裡推薦看這篇博客,寫的很好,裡面對重要欄位進行了說明:https://www.cnblogs.com/shy-huiying/p/5636274.html
3.1 後端實現
3.1.1 獲得本機所有網卡介面信息
Jpcap提供了方法JpcapCaptor.getDeviceList()
完成這個任務,該方法返回一組NetworkInterface對象。
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
/**
* 這裡是controller層
* 獲得所有網卡介面
* @return List<String>
*/
@RequestMapping("/info")
public Object getNetworkCard(){
// 獲取網路介面列表,返回所有的網路設備數組;
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
if (devices.length == 0) {
return "無網卡信息";
}else{
List<NetworkCardPojo> netList = new ArrayList<>();
int index = 0;
for (NetworkInterface n : devices) {
//NetworkCardPojo是自己編寫的實體類,包含網卡介面索引和網卡介面名兩個屬性
NetworkCardPojo networkCardPojo = new NetworkCardPojo();
networkCardPojo.setIndex(index++);
networkCardPojo.setDescription(n.description);
//networkCardPojo.setNetworkInterface(n);
netList.add(networkCardPojo);
}
return netList;
}
}
public class NetworkCardPojo {
private Integer index;
private String description;
//private NetworkInterface NetworkInterface;
}
返回到前端的數據:
3.1.2 得到指定網卡的具體信息
- NetworkInterface[] devices = JpcapCaptor.getDeviceList();得到多有網卡信息
- devices[index].addresses;根據前端傳入的網卡介面索引得到指定網卡介面的信息。
/**
* 這裡是controller層
* 列印選擇網卡的IP地址和子網掩碼;
* @param index
* @return
*/
@RequestMapping("/local")
public LocalParameterPojo getLocalParameter(@ProbeParam("index") Integer index){
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
//根據傳入的網卡索引獲取該網卡介面所屬的IP地址
NetworkInterfaceAddress[] device = devices[index].addresses;
//LocalParameterPojo是自己編寫的實體類,包含本機IP地址、子網掩碼、網路連接類型
LocalParameterPojo local = new LocalParameterPojo();
if (device.length>0){
local.setIpv4(device[0].address);
local.setSubnetMask(device[0].subnet);
local.setNetType(devices[0].datalink_description);
}else {
local.setNetType("該網卡介面不可用,請嘗試切換其他網卡介面!");
}
return local;
}
LocalParameterPojo實體類,註意部分欄位是InetAddress
類型
public class LocalParameterPojo {
private InetAddress ipv4; //本機IP地址
private InetAddress SubnetMask; //子網掩碼
private String netType; //網路連接類型
}
3.1.3 監控ip包數據
因為一個ip地址會發送多個ip包,這裡主要是將ip包進行分組統計:
IP地址--累計IP包數量--累計IP包大小
這裡寫的不好,有些問題,甚至問題很大,後面想到有更好的解決方法,但是沒有嘗試過,就不寫了
/**
* 這裡是controller層
* 開啟監控ip包流量監控
* @param index
* @return
*/
@RequestMapping("/start")
public List<TargetParameterPojo> startGetPacket(@ProbeParam("index") Integer index){
targetParameter.startThread(index);
//根據Ip地址分組
Map<InetAddress, IpGroup> mapAll = new HashMap<>();
System.out.println("ip count:"+targetParameter.getTargetMap().size());
for (int i=0;i<targetParameter.getTargetMap().size();i++){
IpGroup ipGroup = new IpGroup();
for (InetAddress key:targetParameter.getTargetMap().get(i).keySet()){
Integer size = targetParameter.getTargetMap().get(i).get(key);
int count=1;
//檢查 hashMap 中是否存在指定的 key 對應的映射關係。
if(mapAll.containsKey(key)){
Integer tempSize = mapAll.get(key).getSize();
size += tempSize;
Integer tempCount = mapAll.get(key).getCount();
count += tempCount;
}
ipGroup.setCount(count);
ipGroup.setSize(size);
mapAll.put(key,ipGroup);
}
}
// 將數據裝到TargetParameterPojo
List<TargetParameterPojo> targetList = new ArrayList<>();
for (Map.Entry<InetAddress,IpGroup> map:mapAll.entrySet()){
TargetParameterPojo targetPojo = new TargetParameterPojo();
targetPojo.setSourceIp(map.getKey());
targetPojo.setSize(map.getValue().getSize());
targetPojo.setCount(map.getValue().getCount());
targetList.add(targetPojo);
}
return targetList;
}
/**
* 關閉監控ip包流量
* @return
*/
@RequestMapping("/stop")
public int stopsGetPacket(){
int flag = targetParameter.getTargetMap().size();
if(flag>1){
targetParameter.stopThread();
return 1;
}else {
return 0;
}
}
service層
@Service
public class TargetParameter implements Runnable{
//數據統計要用到的list
private static List<Map<InetAddress,Integer>> targetMap = new ArrayList<>();
private boolean flag = true;
private TargetParameter tp;
private Thread thread;
private Integer isOff=0;
public TargetParameter(JpcapCaptor jpcap) {
this.jpcap = jpcap;
}
private JpcapCaptor jpcap = null;
public TargetParameter() {
}
public List<Map<InetAddress, Integer>> getTargetMap() {
return targetMap;
}
@Override
public void run() {
//只要不停止就一直進行抓包
while (flag){
IPPacket ipPacket = (IPPacket) jpcap.getPacket();
if (ipPacket!=null){
Map<InetAddress,Integer> map = new HashMap<>();
map.put(ipPacket.src_ip,ipPacket.len);
targetMap.add(map);
}
// 回調方法
//jpcap.processPacket(-1, new CallbackService());
}
}
/**
* 開啟線程方法
*/
public void startThread(Integer index){
if (isOff==0){
try {
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
//獲得了JpcapCaptor實例就可以用來捕獲來自網路介面的數據包。
//網卡索引,捕獲數據包大小,是否開啟混雜模式(混雜模式會捕獲到數據表),超時
jpcap = JpcapCaptor.openDevice(devices[index], 1024, true, 1000);
// 在捕獲前先設置過濾;
jpcap.setFilter("ip", true);
} catch (IOException e) {
e.printStackTrace();
System.out.println("抓取數據包時出現異常!!");
}
tp = new TargetParameter(jpcap);
//創建一個抓抓包線程,保證一直進行抓包
thread = new Thread(tp);
thread.start();
System.out.println("thread.getName():"+thread.getName());
isOff++;
}
}
/**
* 關閉線程並清空List
*/
public void stopThread(){
isOff=0;
tp.flag=false;
targetMap.clear();
System.out.println(targetMap);
}
}
Pojo:
public class TargetParameterPojo {
private InetAddress sourceIp;
private Integer count;
private Integer size;
}
public class IpGroup {
private Integer size;
private Integer count;
}
3.1.4 目錄結構
3.2 前端實現
前端實現很簡單,主要是數據渲染,這裡說一下我的思路:
- 設定一個計時器,每隔1秒鐘就請求一次數據,從而進行數據更新(axios實現)
- 可根據需要對數據進行排序和截取,比如截取前20條數據進行排序(數據條數太多會造成圖形不美觀)
- 優化:對開啟和關閉按鈕進行控制,防止重覆請求和重覆關閉
4)END
資源下載
鏈接:https://pan.baidu.com/s/1y6u-V-FPwOgIxC9ZoAD7yg
提取碼:1111
內容:
- Jpcap中文API文檔
- npcap-1.72.exe
- Jpcap.dll
- jpcap.jar
- network_vue(前端代碼,需要自己裝包:
npm install
) - network_course_design(Java代碼)
重要:請勿學習如上代碼的寫法,那時候vue正在學,還行學完,代碼冗餘嚴重。
本博客僅僅提供解決方法!歡迎討論,感謝批評指正。