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

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

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

8f9db1a90251e17a980cbf11d41be22a.png

从上图看,所有的应用实例,也就是调用网络协议,实现数据收发功能的应用都继承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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值