
1. 引言
IP就是真实流量,是有人真正浏览了您的网站而产生的流量,每台电脑只有一个IP地址,所以一个IP就是一个人,反映在统计上就是IP数量,IP是Internet Protocol(因特网协议)的缩写,它是通过计算机网络进行交流的最常用的协议之一。
IP监控解决方案就是通过有线或者无线IP网络把视频信息以数字化的形式来进行传输。只要是网络可以到达的地方就一定可以实现视频监控和记录,并且这种监控还可以与很多其它类型的系统进行完美的结合,无论是由模拟摄像机加视频服务器组成的解决方案,还是单独由网络摄像机组成的解决方案,或者是两者混合组成的解决方案,IP监控都已被证明是一种极具吸引力的解决方案。在越来越多的原有行业应用中,这种性的技术正在逐步取代传统的监控系统,在提高安全性的同时也进一步的降低了成本;而在许多新的应用领域,它还是第一次用到,也因此开创和激发了许多新的市场。正是由于它系统的可扩展性,IP监控逐渐巩固了其在现有监视和远程监控行业应用的地位,也加速了在其他新兴行业的应用,监控本地网络,捕获一段时间内以本机为源或目的地址的IP数据包,统计IP数据的信息,列出本机到相同目的地址或同一源地址到本机且数据包协议类型相同的据包的数量。
IP协议的目标很简单:生成发往目的地的数据报,而且除了把这个数据包发送到下一跳路由器之外,不需要担心任何事情。实际上,IP协议很复杂,否则,IP数据报头就不需要那么多的字段。认真研究IP数据报头是非常重要的。IP协议负责接收和发送指定IP地址数据包。但是,IP协议并不保证数据传递的可靠性。
1.1 设计目的
随着网络技术的飞速发展,链路容量和设备处理能力不断升级,Internet的规模呈爆炸性增长,社会对Internet的依赖性越来越高,随之而来,网络传输的业务类型已从简单的低带宽要求的文件传送、电子邮件等变为数据、语音、视频等大流量业务,并且,业务对可靠性,实时性,安全性传输的要求越来越高。基于IP协议的应用成为网络技术研究与软件开发的一个重要基础,因此学习网络层以基本概念,了解IP协议的基本内容,对于掌握TCP/IP协议的主要内容和学习网络课程是十分重要的,通过本次课程设计,有助于熟悉IP包格式和加深对IP协议的理解。
1.2 课程设计内容
编制程序,监控网络,捕获一段时间内网络上的IP数据包,按IP数据包的源地址和目的地址统计出该源地址在该时间段内发出的IP包的个数,将其统计结果在控制台现实出来。
程序的具体要求如下:
(1) 获取网络设备列表。
(2) 选择网卡并打开。
(3) 当捕获数据包时,可能需要设置过滤器。
(4) 捕获数据包或者发送数据包。
(5) 统计数据的流量。
2. 相关知识介绍
2.1 IP流量分析
2.1.1 网间协议IP
IP协议直接位于2层数据链路层之上,负责生成发往目的地的数据报。IP协议原来在RFC 791中定义,后来进行了修改并且进行了多次重新修订。但是,IP协议的基本设计思想仍没有变。IP层不提供任何类型的流量控制或者排序功能。这些功能留给上层。我们将使用“数据报” (datagram)这个词汇指一个完整的IP信息,使用“数据包”(packet)这个词汇指一个单个的IP数据包。
IP协议负责接收和发送指定IP地址数据包。但是,IP协议并不保证数据传递的可靠性。在IP协议层中没有“重试一下”的概念。由于各种原因,数据包有可能出现丢失、损坏、重复、不按照顺序传递或者延迟等问题。IP协议还负责处理IP选项并且以ICMP错误和控制消息等方式提供反馈信息。
IP协议的特点:
(1) IP协议是一种不可靠,无联系的数据包传送协议;
(2) IP协议是点对点的网络层通信协议;
(3) IP协议向传输层隐藏了物理网络的差异。
2.1.2 IP实现网络互连
各个厂家生产的网络系统和设备,如以太网、分组交换网等,它们相互之间不能互通,不能互通的主要原因是因为它们所传送数据的基本单元(技术上称之为“帧”)的格式不同。IP协议实际上是一套由软件程序组成的协议软件,它把各种不同“帧”统一转换成“IP数据包”格式,这种转换是因特网的一个最重要的特点,使所有各种计算机都能在因特网上实现互通,即具有“开放性”的特点。
数据包也是分组交换的一种形式,就是把所传送的数据分段打成 “包”,再传送出去。但是,与传统的“连接型”分组交换不同,它属于“无连接型”,是把打成的每个“包”(分组)都作为一个“的报文”传送出去,所以叫做“数据包”。这样,在开始通信之前就不需要先连接好一条电路,各个数据包不一定都通过同一条路径传输,所以叫做“无连接型”,它大大提高了网络的坚固性和安全性。
每个数据包都有包头和包文这两个部分,包头中有目的地址等必要内容,使每个数据包不经过同样的路径都能准确地到达目的地。在目的地重新组合还原成原来发送的数据。这就要IP具有分组打包和集合组装的功能。在实际传送过程中,数据包还要能根据所经过网络规定的分组大小来改变数据包的长度,IP数据包的最大长度可达 65535个字节。
图2.1 IP数据报格式
IP协议中还有一个非常重要的内容,那就是给因特网上的每台计算机和其它设备都规定了一个唯一的地址,叫做“IP 地址”。由于有这种唯一的地址,才保证了用户在连网的计算机上操作时,能够高效而且方便地从千千万万台计算机中选出自己所需的对象来。现在电信网正在与 IP网走向融合,以IP为基础的新技术是热门的技术,如用IP网络传送话音的技术(即VoIP)就很热门,其它如IP over ATM、IPover SDH、IP over WDM等等,都是IP技术的研究重点。
2.2 JPCAP的简介
Java,是由Sun Microsystems公司于1995年5月推出的Java程序设计语言和Java平台的总称。用Java实现的HotJava浏览器(支持Java applet)显示了Java的魅力:跨平台、动态的Web、Internet计算。但众所周知,Java语言虽然在TCP/UDP传输方面给予了良好的定义,但对于网络层以下的控制,却是为力的。JPCAP扩展包弥补了这一点。
JPCAP是一个能够捕获、发送网络数据包的Java类库包。这个包用到了Libpcap和原始套接字API。
JPCAP实际上并非一个真正去实现对数据链路层的控制,而是一个中间件,JPCAP调用wincap/libpcap,而给 Java语言提供一个公共的接口,从而实现了平台无关性。
在官方网站上声明,JPCAP支持FreeBSD 3.x, Linux RedHat 6.1, Fedora Core 4, Solaris, and Microsoft Windows 2000/XP等系统。
JPCAP的整个结构大体上跟wincap/libpcap是很相像的,例如 NetworkInterface类对应wincap的typedef struct _ADAPTERADAPTER,getDeviceList()对应pcap_findalldevs()等等。
3. 系统设计
3.1设计规划
3.1.1 扫描目标的选取
综合笔者现阶段技术水平和课程设计要求的考虑,通过设计程序来扫描IP包流量信息。同时扫描程序能扫描出MAC地址,网卡信息。然后通过用户选择网卡号,时间来捕获IP数据流量,并且最后把捕获数据总数显示出来。
本课题通过编制程序来监控网络,捕获一段时间内网络上的IP数据包,按IP数据包的源地址和目的地址统计出该源地址在该时间段内发出的IP包的个数,将其统计结果在控制台现实出来。
该程序的主要流程结构:
(1)取得当前网络设备列表(在MyEclipse 6.5控制台输出上显示,以让用户进行选择)。通过使用JpcapCaptor类中的静态方法getDeviceList来获取可以获取IP包的网卡的信息并存在都NetworkInterface数组中,然后在遍历数组将各个网卡的信息打印到控制台上。
(2)将用户选择的网卡打开并设定抓包时间。在控制台接受用户选择网卡的号码和抓包时间后调用抓包方法来打开相对应的网卡和设定抓包时间。
(3)设置过滤器,此处的过滤器“IP”,开始捕获数据包。通过调用JpcapCaptor类的静态方法openDevice打开指定的网卡后并返回一个JpcapCaptor类的实例,然后用该实例调用方法setFilter来设定为IP过滤,从而捕获IP数据包。
(4)捕获IP包并按包的源地址和目的地址进行统计。从文本中读取数据包的信息,将源地址和目的地址提取出来建表,根据源地址和目的地址来进行数据包流量的统计。
如图3.1所示。
图3.1 程序流程图
3.2 各模块工作原理及设计
IP包流量分析程序的设计共包括四个模块,分别为:
(1)获取网络设备列表;
(2)用户选择网卡,接收数据包;
(3)设置过滤器,新建文本存放数据包信息;
(4)捕获IP包并按包的源地址和目的地址进行统计。
3.2.1 获取网络设备列表
(1)工作原理:通过使用JpcapCaptor类中的静态方法getDeviceList来获取可以获取IP包的网卡的信息并存在都NetworkInterface数组中,然后在遍历数组将各个网卡的信息打印到控制台上。
(2)代码实现:
// 获取网络接口列表
public static void getDevices() { //静态方法getDevices
NetworkInterface[] devices = JpcapCaptor.getDeviceList();//获取网络接口
for (int i = 0; i < devices.length; i++) { //循环输出接口信息
System.out.println(i + ": " + devices[i].name + "("
+ devices[i].description + ")");
System.out.println(" datalink: " + devices[i].datalink_name + "("
+ devices[i].datalink_description + ")");
System.out.print(" MAC address:");
for (byte b : devices[i].mac_address)//根据MAC地址来显示输出信息
System.out.print(Integer.toHexString(b & 0xff) + ":");
System.out.println(); //变成十进制显示
for (NetworkInterfaceAddress a : devices[i].addresses)
System.out.println(" address:" + a.address + " " + a.subnet
+ " " + a.broadcast);/ /输出格式
}
}
3.2.2 选择网络
(1)此模块为用户选择网卡,从而接收数据包。工作原理:在控制台接受用户选择网卡的号码和抓包时间后调用抓包方法来打开相对应的网卡和设定抓包时间。
(2)代码实现:
Scanner console = new Scanner(System.in);
getDevices();//显示PC机上可用的网卡的信息
System.out.println("请输入网卡号<0-2>");
int num = console.nextInt();//获取用户要打开的网卡号
System.out.println("请输入抓包时间(分钟)");
int minuets = console.nextInt();//获取用户抓包时间
oneByOneReceiver(num, minuets);//调用抓包方法
3.2.3 设置过滤器
(1)次模块为设置过滤器,并通过新建文本存放数据包信息。工作原理:通过调用JpcapCaptor类的静态方法openDevice打开指定的网卡后并返回一个JpcapCaptor类的实例,然后用该实例调用方法setFilter来设定为IP过滤,从而捕获IP数据包。
(2)代码实现:
// 使用逐个捕获方法, 从网络接口捕获数据包
public static void oneByOneReceiver(int index, int time) throws IOException {
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
JpcapCaptor captor = JpcapCaptor.openDevice(devices[index], 65535,
false, 20);
PrintWriter pw = new PrintWriter(new FileWriter(new File("packets.txt")));
//打印流信息
captor.setFilter("ip", true); // 设置过滤器
int counter = 0;
Packet packet; //定义接受包类
long startTime = System.currentTimeMillis(); //得到当前时间
while (startTime + time * 60 * 10 >= System.currentTimeMillis()) {
packet = captor.getPacket(); //控制显示循环
System.out.println(packet); //输出包信息
if (packet != null) { //if判断包为空的信息
String ips = packet.toString().split("\\\\s+")[1]; //把包信息转换字符串
pw.write(ips); //往里边写入ips信息
pw.println(); //把写入的信息输出
counter++; //循环
}
}
pw.close(); //关闭流
CounterPackets cp = new CounterPackets (); //创建一个CounterPackets对象
cp.readPackets(); //读取包信息
cp.print();
System.out.println("PacketNumbers:" + counter); //输出包的数量
}
3.2.4 捕获IP包
(1)次模块为捕获IP包并按包的源地址和目的地址进行统计。工作原理:从文本中读取数据包的信息,将源地址和目的地址提取出来建表,根据源地址和目的地址来进行数据包流量的统计。
(2)代码实现:
public class CounterPackets {
ArrayList HashMap public CounterPackets() { counter = new HashMap } //从packet.txt.中读取捕获到的IP数据包信息 public void readPackets() throws IOException { ips = new ArrayList BufferedReader br = new BufferedReader(new FileReader("packets.txt")); while (br.read() != -1) { ips.add(br.readLine()); } counter(); } //统计流量 public void counter() { for (int i = 0; i < ips.size(); i++) { String[] result = getIps(ips.get(i)); String index = result[0] + " " + result[1]; setNumber(index); } } //获取源地址和目的地址 public String[] getIps (String ips) { StringBuffer sb = new StringBuffer(ips); for (int i = 0; i < ips.length(); i++) { if (ips.charAt(i) == '/' || ips.charAt(i) == '>' || ips.charAt(i) == '-') { sb.replace(i, i + 1, " "); } } ips = sb.toString().trim(); return ips.split("\\\\s+"); } //数目叠加 public void setNumber(String index) { if (counter.containsKey(index)) { int value = counter.get(index); counter.put(index, value+1); } else { counter.put(index, 1); } } //将结果打印到控制台 public void print() { System.out.println("源地址" + " " + "目的地址" + " " + "PacketNumber"); Iterator it = counter.keySet().iterator(); //定义遍历类 while (it.hasNext()) { //while控制循环 String index = (String) it.next(); //从it中得到下一个字符串 String[] ips = index.split("\\\\s+"); //切割成字符串数组 String srcIp = String.format("%-6s", ips[0]); String dstIp = ips[1]; int number = counter.get(index); System.out.println(srcIp + " " + dstIp + " " + number);//输出信息 } } } 4 运行结果 4.1 获取网络设备列表 运行程序,扫描到PC机当前网络设备列表,格式以网卡号加网卡设备参数以及MAC地址信息。选择网卡号,进行IP流量扫描。如图4.1所示。 图4.1 当前网络设备列表 4.2 选择网卡 扫描出网卡信息后,然后选择网卡后,用户选择抓包时间进行扫描,如图4.2所示. 图4.2 用户选择时间操作 4.3 设置过滤器 当开始程序运行时,扫描出用户PC的网卡信息,然后选择网卡号和抓包世界,然后开始捕获IP数据包的信息,程序运行后,会捕获到该时间段网卡的IP流量信息,然后显示再控制台。如图4.3所示。 图4.3 捕获IP数据包的信息 4.4 捕获IP包 程序捕获数据包的过程中,首先显示如图4.3的流量监控形式。然后以源地址,目的地址,包数量的形式进行统计,显示再控制台。IP数据包流量统计的结果,如图4.4所示。 图4.4 统计结果 5.结束语 5.1 课程设计应有的态度 本人认为,程序设计目的在于开阔眼界,把课本知识联系实际实践,给予学生处理实际问题的机会,而不应该只是一味地从网上搜索,这种快餐式文化,显然是与课程设计的目的背道而驰的。课程设计的目的是培养学生综合运用所学知识,发现,提出,分析和解决实际问题,锻炼实践能力。对大三学生来说,更应该重视与珍惜课程设计,因为这是个很好的实践机会,然后应该深入了解题目,理清思路,通过课程设计培养联系实际和解决实际问题的能力。 5.2 课程设计心得体会 为期两周的课程设计结束了,但它却给我留下深刻的印象:我清楚的感到,随着科技的发展以及计算机网络在各行各业的广泛应用,计算机网络以自己的独特的优点在我们的生活中占据着重要的位置。通过本课程设计的学习,我对计算机网络的基本系统有了比较深刻的理解。 以前对于编程工具的使用还处于一知半解的状态上,但是经过一段上机的实践,对于怎么去排错、查错,怎么去看每一步的运行结果。通过这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,才能真正为社会服务,从而提高自己的实际动手能力和思考的能力。在设计的过程中遇到问题,可以说得是困难重重,同时在设计的过程中发现了自己的不足之处,以前所学过的知识理解得不够深刻,掌握得不够牢固。不论是做学问,还是为人处事,首先,我们要明确目的,该做什么不该做什么。其次,分析问题,理清思路,时刻保持清醒的头脑。最后,还要有信心,恒心和不怕失败的决心。我会把我的收获带到以后的学习生活中,端正生活和学习的态度,永远追求积极向上的生活。 参考文献 [1] 吴功宜 胡晓英.计算机网络课程设计 北京:机械工业出版社,2007.12. [2] 王春晓 赵艳标.计算机网络教程 北京:机械工业出版社,2005.08. [3] 谢希仁.计算机网络[M].北京:电子工业出版社,2009. [4] (美)埃克尔 著,陈昊鹏 译. Java编程思想(第4版)北京:机械工业出版社,2007.06.01 [5] (美)Y.Daniel Liang 著,万波 译.Java语言程序设计(第6版) 北京:机械工业出版社,2008.06. 附录 程序名:TestJpcap.java import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.Scanner; import jpcap.JpcapCaptor; import jpcap.NetworkInterface; import jpcap.NetworkInterfaceAddress; import jpcap.packet.Packet; public class TestJpcap { public static void main(String[] args) throws IOException { Scanner console = new Scanner(System.in); getDevices();//显示PC机上可用的网卡的信息 System.out.println("请输入网卡号<0-2>"); int num = console.nextInt();//获取用户要打开的网卡号 System.out.println("请输入抓包时间(分钟)"); int minuets = console.nextInt();//获取用户抓包时间 oneByOneReceiver(num, minuets);//调用抓包方法 } // 获取网络接口列表 public static void getDevices() { NetworkInterface[] devices = JpcapCaptor.getDeviceList(); for (int i = 0; i < devices.length; i++) { System.out.println(i + ": " + devices[i].name + "(" + devices[i].description + ")"); System.out.println(" datalink: " + devices[i].datalink_name + "(" + devices[i].datalink_description + ")"); System.out.print(" MAC address:"); for (byte b : devices[i].mac_address) System.out.print(Integer.toHexString(b & 0xff) + ":"); System.out.println(); for (NetworkInterfaceAddress a : devices[i].addresses) System.out.println(" address:" + a.address + " " + a.subnet + " " + a.broadcast); } } // 使用逐个捕获方法, 从网络接口捕获数据包 public static void oneByOneReceiver(int index, int time) throws IOException { NetworkInterface[] devices = JpcapCaptor.getDeviceList(); JpcapCaptor captor = JpcapCaptor.openDevice(devices[index], 65535, false, 20); PrintWriter pw = new PrintWriter(new FileWriter(new File("packets.txt"))); // 设置过滤器 captor.setFilter("ip", true); int counter = 0; Packet packet; long startTime = System.currentTimeMillis(); while (startTime + time * 60 * 10 >= System.currentTimeMillis()) { packet = captor.getPacket(); System.out.println(packet); if (packet != null) { String ips = packet.toString().split("\\\\s+")[1]; pw.write(ips); pw.println(); counter++; } } pw.close(); CounterPackets cp = new CounterPackets(); cp.readPackets(); cp.print(); System.out.println("PacketNumbers:" + counter); } } 程序名: CounterPackets.java import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; public class CounterPackets { ArrayList HashMap public CounterPackets() { counter = new HashMap } //从packet.txt.中读取捕获到的IP数据包信息 public void readPackets() throws IOException { ips = new ArrayList BufferedReader br = new BufferedReader(new FileReader("packets.txt")); while (br.read() != -1) { ips.add(br.readLine()); } counter(); } //统计流量 public void counter() { for (int i = 0; i < ips.size(); i++) { String[] result = getIps(ips.get(i)); String index = result[0] + " " + result[1]; setNumber(index); } } //获取源地址和目的地址 public String[] getIps (String ips) { StringBuffer sb = new StringBuffer(ips); for (int i = 0; i < ips.length(); i++) { if (ips.charAt(i) == '/' || ips.charAt(i) == '>' || ips.charAt(i) == '-') { sb.replace(i, i + 1, " "); } } ips = sb.toString().trim(); return ips.split("\\\\s+"); } //数目叠加 public void setNumber(String index) { if (counter.containsKey(index)) { int value = counter.get(index); counter.put(index, value+1); } else { counter.put(index, 1); } } //将结果打印到控制台 public void print() { System.out.println("源地址" + " " + "目的地址" + " " + PacketNumber"); Iterator it = counter.keySet().iterator(); while (it.hasNext()) { String index = (String)it.next(); String[] ips = index.split("\\\\s+"); String srcIp = String.format("%-6s", ips[0]); String dstIp = ips[1]; int number = counter.get(index); System.out.println(srcIp + " " + dstIp + " " + number); } } }
