在原先代码设计中,我们为了方便,喜欢在一个模块中组织数据包的协议头,然后将要发送的数据融合在一起,并调用网卡将数据发送出去,这种偷懒的做法将多种逻辑融合在一起。这种做法一旦遇到复杂的数据发送需求时,系统逻辑的复杂性会呈现出爆炸性的增长,最后超出我们的控制范围。
为了实现体系的层次化,将各种功能剥离成单独模块,实现系统的可理解性,我将体系结构改动为以下模式:
![8f9db1a90251e17a980cbf11d41be22a.png](https://i-blog.csdnimg.cn/blog_migrate/254aeb7e9cd60ce3d810f84644a53877.jpeg)
从上图看,所有的应用实例,也就是调用网络协议,实现数据收发功能的应用都继承IApplication接口和继承Application类,其内容如下:
package Application;import java.util.HashMap;public interface IApplication { public int getPort(); public boolean isClosed(); public void handleData(HashMap data);}package Application;import java.util.HashMap;public class Application implements IApplication{ protected int port = 0; private boolean closed = false; public Application() { ApplicationManager manager = ApplicationManager.getInstance(); manager.addApplication(this); } @Override public int getPort() { return port; } @Override public void handleData(HashMap data) { // TODO Auto-generated method stub } @Override public boolean isClosed() { return closed; }}
所有应用对象都要导出getPort()接口,每个port对应唯一一个应用对象,如果数据包到达后,协议会根据port寻找应该接受数据的应用对象。应用对象全部接受ApplicationManager的管理,当网络协议部分有数据需要提交给对应的应用时,需要通过ApplicationManager查询相应应用对象,它的代码如下:
package Application;import java.util.ArrayList;public class ApplicationManager { private static ArrayList application_list = new ArrayList(); private static ApplicationManager instance = null; private ApplicationManager() { } public static ApplicationManager getInstance() { if (instance == null) { instance = new ApplicationManager(); } return instance; } public static void addApplication(IApplication app) { application_list.add(app); } public IApplication getApplicationByPort(int port) { for (int i = 0; i < application_list.size(); i++) { IApplication app = application_list.get(i); if (app.getPort() == port) { return app; } } return null; }}
实现网络协议的模块单独形成一个独立部分,实现具体网络协议的对象都继承统一的接口IProtocol:
package protocol;import java.util.HashMap;import jpcap.packet.Packet;public interface IProtocol { public byte[] createHeader(HashMap headerInfo); public HashMap handlePacket(Packet packet);}
所有协议对象都接受ProtocolManager的统一管理,当应用对象需要调用某个协议对象创建包头时,需要经过ProtocolManager获取相应对象,同时它是唯一一个从网卡接收数据的对象,当网卡把数据包传递给它后,它通过解析网络包的以太太包头,决定把数据包转交给对应的网络协议对象解析,它的代码如下:
package protocol;
import java.util.Arrays;
import java.util.HashMap;
import Application.ApplicationManager;
import Application.IApplication;
import datalinklayer.DataLinkLayer;
import jpcap.PacketReceiver;
import jpcap.packet.EthernetPacket;
import jpcap.packet.IPPacket;
import jpcap.packet.Packet;
public class ProtocolManager implements PacketReceiver{
private static ProtocolManager instance = null;
private static ARPProtocolLayer arpLayer = null;
private static DataLinkLayer dataLinkInstance = null;
private static HashMap ipToMacTable = null;
private static HashMap dataWaitToSend = null;
private static byte[] broadcast=new byte[]{(byte)255,(byte)255,(byte)255,(byte)255,(byte)255,(byte)255};
private ProtocolManager() {}
public static ProtocolManager getInstance() {
if (instance == null) {
instance = new ProtocolManager();
dataLinkInstance = DataLinkLayer.getInstance();
ipToMacTable = new HashMap();
dataWaitToSend = new HashMap();
dataLinkInstance.registerPacketReceiver(instance);
arpLayer = new ARPProtocolLayer();
}
return instance;
}
public IProtocol getProtocol(String name) {
switch (name.toLowerCase()) {
case "icmp":
return new ICMPProtocolLayer();
case "ip":
return new IPProtocolLayer();
}
return null;
}
public void sendData(byte[] data, byte[] ip) throws Exception {
/*
* 发送数据前先检查给定ip的mac地址是否存在,如果没有则先让ARP协议获取mac地址
*/
byte[] mac = ipToMacTable.get(Arrays.toString(ip));
if (mac == null) {
HashMap headerInfo = new HashMap();
headerInfo.put("sender_ip