从0到1用java再造tcpip协议栈:架构重建,完整实现ping应用

在原先代码设计中,我们为了方便,喜欢在一个模块中组织数据包的协议头,然后将要发送的数据融合在一起,并调用网卡将数据发送出去,这种偷懒的做法将多种逻辑融合在一起。这种做法一旦遇到复杂的数据发送需求时,系统逻辑的复杂性会呈现出爆炸性的增长,最后超出我们的控制范围。

为了实现体系的层次化,将各种功能剥离成单独模块,实现系统的可理解性,我将体系结构改动为以下模式:

1.png

从上图看,所有的应用实例,也就是调用网络协议,实现数据收发功能的应用都继承IApplication接口和继承Application类,其内容如下:

package Application;

import java.util.HashMap;

public interface IApplication {
    public  int getPort();
    public boolean isClosed(); 
    public  void handleData(HashMap<String, Object> 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<String, Object> 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<IApplication> application_list = new ArrayList<IApplication>();
	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<String, Object> headerInfo);
    public HashMap<String, Object> 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<String , byte[] > ipToMacTable = null;
	private static HashMap<String, byte[]> 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<String, byte[]>();
			dataWaitToSend = new HashMap<String, byte[]>();
			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<String, Object> headerInfo = new HashMap<String, Object>();
    		headerInfo.put("sender_ip", ip);
    		byte[] arpRequest = arpLayer.createHeader(headerInfo);
    		if (arpRequest == null) {
    			throw new Exception("Get mac adress hea
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值