From 9eb82869f2fc228d6b445e6a18374fe699130f9d Mon Sep 17 00:00:00 2001 From: xking Date: Sun, 1 Dec 2024 01:53:27 +0800 Subject: [PATCH] init --- src/main/java/cn/x47/RIPService.java | 14 +- .../java/cn/x47/handle/RIPPacketDecoder.java | 1 + .../java/cn/x47/handle/RIPPacketEncoder.java | 2 +- .../java/cn/x47/handle/RIPServerHandler.java | 12 +- src/main/java/cn/x47/model/RIPPacket.java | 4 +- src/main/java/cn/x47/service/RIPClient.java | 14 +- .../java/cn/x47/service/RoutingTable.java | 35 +++ src/test/java/Connection.java | 285 ++++++++++++++++++ 8 files changed, 341 insertions(+), 26 deletions(-) create mode 100644 src/main/java/cn/x47/service/RoutingTable.java create mode 100644 src/test/java/Connection.java diff --git a/src/main/java/cn/x47/RIPService.java b/src/main/java/cn/x47/RIPService.java index 3b51a6a..efc847f 100644 --- a/src/main/java/cn/x47/RIPService.java +++ b/src/main/java/cn/x47/RIPService.java @@ -10,7 +10,9 @@ import cn.x47.service.RIPServer; import java.net.InetAddress; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.*; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; public class RIPService { @@ -31,11 +33,13 @@ public class RIPService { // 定期发送路由更新 ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); scheduler.scheduleAtFixedRate(() -> { + System.out.println("发送 开始"); RIPPacket packet = createRipResponsePacket(Config.RIP_VERSION); client.sendRipPacket(packet); - }, 0, 30, TimeUnit.SECONDS); + System.out.println("发送 结束"); + }, 0, 10, TimeUnit.SECONDS); -// 主线程等待 + // 主线程等待 Thread.currentThread().join(); } @@ -44,9 +48,9 @@ public class RIPService { try { // 示例:添加本地路由条目 - InetAddress localAddress = InetAddress.getByName("192.168.100.0"); + InetAddress localAddress = InetAddress.getByName("10.47.54.0"); InetAddress subnetMask = InetAddress.getByName("255.255.255.0"); - InetAddress nextHop = InetAddress.getByName("192.168.123.45"); + InetAddress nextHop = InetAddress.getByName("192.168.192.10"); RIPEntry entry = new RIPEntry(); entry.setAddressFamily((short) 2); // AF_INET diff --git a/src/main/java/cn/x47/handle/RIPPacketDecoder.java b/src/main/java/cn/x47/handle/RIPPacketDecoder.java index fe90c55..6163f48 100644 --- a/src/main/java/cn/x47/handle/RIPPacketDecoder.java +++ b/src/main/java/cn/x47/handle/RIPPacketDecoder.java @@ -1,5 +1,6 @@ package cn.x47.handle; + import cn.x47.model.RIPEntry; import cn.x47.model.RIPPacket; import io.netty.buffer.ByteBuf; diff --git a/src/main/java/cn/x47/handle/RIPPacketEncoder.java b/src/main/java/cn/x47/handle/RIPPacketEncoder.java index c867a10..2cae983 100644 --- a/src/main/java/cn/x47/handle/RIPPacketEncoder.java +++ b/src/main/java/cn/x47/handle/RIPPacketEncoder.java @@ -5,8 +5,8 @@ import cn.x47.model.RIPEntry; import cn.x47.model.RIPPacket; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.socket.DatagramPacket; import io.netty.handler.codec.MessageToMessageEncoder; +import io.netty.channel.socket.DatagramPacket; import java.net.InetSocketAddress; import java.util.List; diff --git a/src/main/java/cn/x47/handle/RIPServerHandler.java b/src/main/java/cn/x47/handle/RIPServerHandler.java index 242795b..dce5a32 100644 --- a/src/main/java/cn/x47/handle/RIPServerHandler.java +++ b/src/main/java/cn/x47/handle/RIPServerHandler.java @@ -3,6 +3,7 @@ package cn.x47.handle; import cn.x47.model.RIPEntry; import cn.x47.model.RIPPacket; +import cn.x47.service.RoutingTable; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; @@ -10,17 +11,12 @@ public class RIPServerHandler extends SimpleChannelInboundHandler { @Override protected void channelRead0(ChannelHandlerContext ctx, RIPPacket msg) throws Exception { - System.out.println(msg); if (msg.getCommand() == 2) { // Response for (RIPEntry entry : msg.getEntries()) { // 更新本地路由表 updateRoutingTable(entry); } - } else if (msg.getCommand() == 1) { - for (RIPEntry entry : msg.getEntries()) { - // 更新本地路由表 - updateRoutingTable(entry); - } + } else if (msg.getCommand() == 1) { // Request // 处理请求,可能需要发送响应包 // ... } @@ -29,8 +25,10 @@ public class RIPServerHandler extends SimpleChannelInboundHandler { private void updateRoutingTable(RIPEntry entry) { // 实现路由表更新逻辑 // 这里只是示例,实际需要处理路由添加、更新、超时等逻辑 - System.out.println("Received route: " + entry.getIpAddress().getHostAddress() + + RoutingTable.getInstance().updateRoute(entry); + System.out.println("Updated route: " + entry.getIpAddress().getHostAddress() + " via " + entry.getNextHop().getHostAddress() + " metric: " + entry.getMetric()); + } } diff --git a/src/main/java/cn/x47/model/RIPPacket.java b/src/main/java/cn/x47/model/RIPPacket.java index 9c71f2f..f7f49d6 100644 --- a/src/main/java/cn/x47/model/RIPPacket.java +++ b/src/main/java/cn/x47/model/RIPPacket.java @@ -4,7 +4,6 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import java.net.InetSocketAddress; import java.util.List; @Data @@ -13,9 +12,8 @@ import java.util.List; public class RIPPacket { private byte command; // 1=Request, 2=Response private byte version; // 1=RIP v1, 2=RIP v2 - private short unused = 0; // 未使用,设置为 0 + private short unused; // 未使用,设置为 0 private List entries; - private InetSocketAddress senderAddress; // 添加构造方法和 Getter/Setter public RIPPacket(byte command, byte version, List entries) { diff --git a/src/main/java/cn/x47/service/RIPClient.java b/src/main/java/cn/x47/service/RIPClient.java index 569cac3..c3a1a19 100644 --- a/src/main/java/cn/x47/service/RIPClient.java +++ b/src/main/java/cn/x47/service/RIPClient.java @@ -11,6 +11,7 @@ import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.nio.NioDatagramChannel; + public class RIPClient { private final Bootstrap bootstrap; @@ -32,21 +33,14 @@ public class RIPClient { public void sendRipPacket(RIPPacket packet) { try { - ChannelFuture future = bootstrap.bind(600).sync(); // 部分环境下需不同端口尝试 - future.channel().writeAndFlush(packet).addListener(f -> { - if (f.isSuccess()) { - System.out.println("Packet sent successfully"); - } else { - System.err.println("Failed to send packet: " + f.cause().getMessage()); - } - }); - future.channel().closeFuture().sync(); // 等待,保持通道开启 + ChannelFuture future = bootstrap.bind(0).sync(); + future.channel().writeAndFlush(packet).sync(); + future.channel().close(); } catch (InterruptedException e) { e.printStackTrace(); } } - public void shutdown() { group.shutdownGracefully(); } diff --git a/src/main/java/cn/x47/service/RoutingTable.java b/src/main/java/cn/x47/service/RoutingTable.java new file mode 100644 index 0000000..7946935 --- /dev/null +++ b/src/main/java/cn/x47/service/RoutingTable.java @@ -0,0 +1,35 @@ +package cn.x47.service; + + + +import cn.x47.model.RIPEntry; + +import java.net.InetAddress; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class RoutingTable { + private static RoutingTable instance = new RoutingTable(); + private Map routes; + + private RoutingTable() { + routes = new ConcurrentHashMap<>(); + } + + public static RoutingTable getInstance() { + return instance; + } + + public void updateRoute(RIPEntry entry) { + // 简单地将新路由添加或更新到路由表中 + routes.put(entry.getIpAddress(), entry); + } + + public void removeRoute(InetAddress ipAddress) { + routes.remove(ipAddress); + } + + public Map getRoutes() { + return routes; + } +} diff --git a/src/test/java/Connection.java b/src/test/java/Connection.java new file mode 100644 index 0000000..65cd854 --- /dev/null +++ b/src/test/java/Connection.java @@ -0,0 +1,285 @@ +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.UnknownHostException; +import java.util.*; + +/** + * Connection class takes input from the user + * and creates threads for the client and server + * + * @author Ankit + */ +public class Connection { + + // Stores destination and cost to reach + public static HashMap table; + // Stores local ip address + static String[] localIP; + // Stores it's neighbors + static ArrayList neighbors; + //Stores destination and next hop + public static HashMap hop; + // Subnet mask + public static String subnetMask = "255.255.255.0"; + + public static void main(String[] args) throws IOException { + table = new HashMap<>(); + hop = new HashMap<>(); + neighbors = new ArrayList<>(); + System.out.println(InetAddress.getLocalHost() + " connection started"); + localIP = InetAddress.getLocalHost().toString().split("/"); + System.out.println("Updated position 1"); + table.put(localIP[1], 0); + hop.put(localIP[1], localIP[1]); + // Starts the server + Server server = new Server(); + server.start(); + + int length = args.length; + // User input for the neighbor ip and cost + Scanner scan = new Scanner(System.in); + for (int i = 0; i < length; i++) { + System.out.println("Enter the cost for " + args[i].toString()); + int cost = scan.nextInt(); + new Client(args[i], cost).start(); + } + scan.close(); + } + + /** + * Updates the destination cost and the next hop + * + * @param temp - routing table of neighbor + * @param senderIP - sender ip address + * @param tempHop - Next hops of the sender + */ + public static void updateTable(Map temp, String senderIP, Map tempHop) { + // updates the table if neighbor has smaller value + if (table.containsKey(senderIP) && temp.containsKey(localIP[1])) { + if (table.get(senderIP) > temp.get(localIP[1])) { + table.put(senderIP, temp.get(localIP[1])); + if (tempHop.get(localIP[1]).equals(localIP[1])) { + hop.put(senderIP, senderIP); + } else { + for (int i = 0; i < neighbors.size(); i++) { + if (!neighbors.get(i).equals(senderIP)) { + hop.put(senderIP, neighbors.get(i)); + } + } + } + + } + } + + // Add the neighbor if neighbor has its entry + if (!table.containsKey(senderIP)) { + table.put(senderIP, temp.get(localIP[1])); + hop.put(senderIP, senderIP); + } + + @SuppressWarnings("rawtypes") + Iterator it = temp.entrySet().iterator(); + while (it.hasNext()) { + @SuppressWarnings("rawtypes") + Map.Entry pair = (Map.Entry) it.next(); + String ip = pair.getKey().toString(); + if (!table.containsKey(ip)) { + table.put(ip, Integer.parseInt(pair.getValue().toString()) + + table.get(senderIP)); + hop.put(ip, senderIP); + } else { + if (table.get(ip) > (Integer.parseInt(pair.getValue() + .toString()) + table.get(senderIP))) { + table.put( + ip, + (Integer.parseInt(pair.getValue().toString()) + table + .get(senderIP))); + hop.put(ip, senderIP); + } + } + } + } + + /** + * Displays the desired output i.e. + * Destination, subnet mask, cost and next hop + */ + public static void display() { + @SuppressWarnings("rawtypes") + Iterator it = table.entrySet().iterator(); + System.out.println("------ UPDATED TABLE -----"); + System.out.println("Destination" + '\t' + "Subnet Mask" + '\t' + "Cost" + '\t' + "Next Hop"); + while (it.hasNext()) { + @SuppressWarnings("rawtypes") + Map.Entry pair = (Map.Entry) it.next(); + String[] ipSubParts = pair.getKey().toString().split("\\."); + String[] subnetSubParts = subnetMask.split("\\."); + String[] netID = new String[4]; + for (int i = 0; i < ipSubParts.length; i++) { + netID[i] = Integer.toString((Integer.parseInt(ipSubParts[i]) & Integer.parseInt(subnetSubParts[i]))); + } + String networkID = netID[0] + "." + netID[1] + "." + netID[2] + "." + netID[3]; + // Desired output displayed + System.out.println(networkID + '\t' + subnetMask + '\t' + pair.getValue() + '\t' + hop.get(pair.getKey().toString())); + } + System.out.println(); + System.out.println("----------------------------------------------"); + } + +} + +/** + * Server class accepts the connection from the neighbors + * It waits for neighbors input, updates table + * and sends updated table + * + * @author Ankit + */ +class Server extends Thread { + + private static ServerSocket server; + private Socket connection; + ObjectInputStream input; + ObjectOutputStream output; + + public Server() throws IOException { + server = new ServerSocket(6969); + } + + public void run() { + try { + accept(); + } catch (UnknownHostException | ClassNotFoundException e) { + e.printStackTrace(); + } + } + + public void accept() throws UnknownHostException, ClassNotFoundException { + try { + int count = 0; + while (count < 2) { + count++; + System.out.println(InetAddress.getLocalHost() + + " is waiting for connection " + count); + // accepts the connection from the neighbors + connection = server.accept(); + System.out.println(InetAddress.getLocalHost() + + " connected to " + connection.getInetAddress()); + String[] connectionIP = connection.getInetAddress().toString() + .split("/"); + Connection.neighbors.add(connectionIP[1]); + output = new ObjectOutputStream(connection.getOutputStream()); + input = new ObjectInputStream(connection.getInputStream()); + + // Creates new thread to interact with the client + new Thread(new Runnable() { + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public void run() { + while (true) { + try { + HashMap, HashMap> receiver; + // reads the input from the neighbor + receiver = (HashMap, HashMap>) input.readObject(); + HashMap temp = (HashMap) receiver.keySet().toArray()[0]; + HashMap tempHop = receiver.get(temp); + @SuppressWarnings("unused") + Iterator it = temp.entrySet().iterator(); + Connection.updateTable(temp, connectionIP[1], tempHop); + HashMap, HashMap> sender; + sender = new HashMap, HashMap>(); + sender.put(Connection.table, Connection.hop); + // sends the updated table to its neighbors + output.writeObject(sender); + output.reset(); + Connection.display(); + Thread.sleep(1000); + } catch (Exception e) { + System.exit(0); + } + } + } + }).start(); + + } + } catch (IOException e) { + System.exit(0); + } + } +} + +/** + * Client asks for the connection to the server + * It sends current routing table and recieves the updated routing table + * + * @author Ankit + */ +class Client extends Thread { + + Socket connection; + String ipAddress = ""; + int cost; + ObjectInputStream input; + ObjectOutputStream output; + + public Client(String ip, int cost) throws IOException { + ipAddress = ip; + this.cost = cost; + } + + @SuppressWarnings({"unused", "unchecked"}) + public void run() { + try { + // connects to the server + connection = new Socket(ipAddress, 6969); + Connection.neighbors.add(ipAddress); + output = new ObjectOutputStream(connection.getOutputStream()); + input = new ObjectInputStream(connection.getInputStream()); + System.out.println(InetAddress.getLocalHost().toString() + + " Connected to: " + ipAddress + " with cost: " + cost); + if (Connection.table.containsKey(ipAddress)) { + if (Connection.table.get(ipAddress) > cost) { + Connection.table.put(ipAddress, cost); + Connection.hop.put(ipAddress, ipAddress); + } + } else { + Connection.table.put(ipAddress, cost); + Connection.hop.put(ipAddress, ipAddress); + } + + while (true) { + Connection.display(); + HashMap, HashMap> sender; + sender = new HashMap, HashMap>(); + sender.put(Connection.table, Connection.hop); + // sends updated cost and next hop table to the neighbor + output.writeObject(sender); + output.reset(); + + HashMap, HashMap> receiver; + // reads updated cost and next hop table from neighbor + receiver = (HashMap, HashMap>) input.readObject(); + HashMap temp = (HashMap) receiver.keySet().toArray()[0]; + HashMap tempHop = receiver.get(temp); + @SuppressWarnings("rawtypes") + Iterator it = temp.entrySet().iterator(); + Connection.updateTable(temp, ipAddress, tempHop); + Thread.sleep(1000); + } + + } catch (UnknownHostException e) { + System.out.println("Cannot connect to the network: " + + e.getMessage()); + } catch (IOException e) { + System.exit(0); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } +}