Compare commits

...

8 Commits
main ... v2

Author SHA1 Message Date
757b781f30
修复组播无法接收 2024-12-01 23:06:34 +08:00
497f55c40c
优化 服务端,客户端代码 解决读取错位的问题。 2024-12-01 20:33:49 +08:00
638507e0f3
优化 服务端 客户端代码 2024-12-01 17:59:34 +08:00
a9afea0603
优化 服务端 客户端代码 2024-12-01 16:50:43 +08:00
6203c43ebe
更改发送报文时 绑定的端口 2024-12-01 16:40:19 +08:00
f379b02e61
fix 修复 rip v1 响应包 不正确 2024-12-01 16:34:38 +08:00
9eb82869f2
init 2024-12-01 01:53:27 +08:00
807df279e9
init 2024-11-30 22:40:06 +08:00
14 changed files with 563 additions and 224 deletions

View File

@ -18,7 +18,7 @@
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.68.Final</version>
<version>4.1.110.Final</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>

View File

@ -8,34 +8,46 @@ import cn.x47.service.RIPClient;
import cn.x47.service.RIPServer;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
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 {
public static void main(String[] args) throws Exception {
// 启动服务器
RIPServer server = new RIPServer();
new Thread(() -> {
try {
server.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
if (Config.startServer) {
RIPServer server = new RIPServer();
new Thread(() -> {
try {
server.start();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (SocketException | UnknownHostException e) {
throw new RuntimeException(e);
}
}).start();
System.out.println("服务端已经启动");
}
// 启动客户端
RIPClient client = new RIPClient();
if (Config.startClient) {
// 启动客户端
RIPClient client = new RIPClient();
// 定期发送路由更新
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(() -> {
RIPPacket packet = createRipResponsePacket(Config.RIP_VERSION);
client.sendRipPacket(packet);
System.out.println("客户端 发送了一次消息");
}, 0, 10, TimeUnit.SECONDS);
System.out.println("客户端已经启动");
}
// 定期发送路由更新
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(() -> {
RIPPacket packet = createRipResponsePacket(Config.RIP_VERSION);
client.sendRipPacket(packet);
}, 0, 30, TimeUnit.SECONDS);
// 主线程等待
// 主线程等待
Thread.currentThread().join();
}
@ -44,9 +56,9 @@ public class RIPService {
try {
// 示例添加本地路由条目
InetAddress localAddress = InetAddress.getByName("192.168.100.0");
InetAddress subnetMask = InetAddress.getByName("255.255.255.0");
InetAddress nextHop = InetAddress.getByName("192.168.123.45");
InetAddress localAddress = InetAddress.getByName("10.110.80.52");
InetAddress subnetMask = InetAddress.getByName("255.255.255.255");
InetAddress nextHop = InetAddress.getByName("0.0.0.0");
RIPEntry entry = new RIPEntry();
entry.setAddressFamily((short) 2); // AF_INET

View File

@ -3,4 +3,6 @@ package cn.x47.config;
public class Config {
// 设置协议版本1 表示 RIP v12 表示 RIP v2
public static final byte RIP_VERSION = 2;
public static final boolean startServer = true;
public static final boolean startClient = true;
}

View File

@ -4,12 +4,14 @@ package cn.x47.handle;
import cn.x47.model.RIPEntry;
import cn.x47.model.RIPPacket;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.DatagramPacket;
import io.netty.handler.codec.MessageToMessageDecoder;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@ -28,37 +30,34 @@ public class RIPPacketDecoder extends MessageToMessageDecoder<DatagramPacket> {
List<RIPEntry> entries = new ArrayList<>();
while (buf.readableBytes() >= 20) {
RIPEntry entry = new RIPEntry();
entry.setAddressFamily((short) buf.readUnsignedShort());
if (ripPacket.getVersion() == 2) {
entry.setRouteTag((short) buf.readUnsignedShort());
} else {
entry.setRouteTag((short) 0);
}
entry.setAddressFamily(buf.readShort());
entry.setRouteTag(buf.readShort());
byte[] ipBytes = new byte[4];
buf.readBytes(ipBytes);
entry.setIpAddress(InetAddress.getByAddress(ipBytes));
if (ripPacket.getVersion() == 2) {
buf.readBytes(ipBytes);
entry.setSubnetMask(InetAddress.getByAddress(ipBytes));
buf.readBytes(ipBytes);
entry.setNextHop(InetAddress.getByAddress(ipBytes));
} else {
buf.readBytes(ipBytes);
entry.setSubnetMask(InetAddress.getByAddress(ipBytes));
buf.readBytes(ipBytes);
entry.setNextHop(InetAddress.getByAddress(ipBytes));
if (ripPacket.getVersion() == 1) {
// 对于 RIP v1子网掩码和下一跳需要推断或设为默认值
entry.setSubnetMask(InetAddress.getByName("255.255.255.0")); // 示例实际应根据 IP 类推断
}
byte[] address = entry.getNextHop().getAddress();
byte[] address1 = InetAddress.getByName("0.0.0.0").getAddress();
if(Arrays.equals(address, address1)) {
entry.setNextHop(packet.sender().getAddress());
}
long metric = buf.readUnsignedInt();
entry.setMetric(metric);
entry.setMetric((int) buf.readUnsignedInt());
entries.add(entry);
}
ripPacket.setEntries(entries);
ripPacket.setSenderAddress(packet.sender()); // 设置发送者地址
out.add(ripPacket);
}
}

View File

@ -25,18 +25,21 @@ public class RIPPacketEncoder extends MessageToMessageEncoder<RIPPacket> {
// 编码路由条目
for (RIPEntry entry : msg.getEntries()) {
buf.writeShort(entry.getAddressFamily() & 0xFFFF);
buf.writeShort(entry.getAddressFamily());
if (msg.getVersion() == 2) {
buf.writeShort(entry.getRouteTag() & 0xFFFF);
buf.writeShort(entry.getRouteTag());
} else if (msg.getVersion() == 1) {
buf.writeShort(0);
}
buf.writeBytes(entry.getIpAddress().getAddress());
if (msg.getVersion() == 2) {
buf.writeBytes(entry.getSubnetMask().getAddress());
buf.writeBytes(entry.getNextHop().getAddress());
} else if (msg.getVersion() == 1) {
buf.writeInt(0);
buf.writeInt(0);
}
buf.writeInt((int) entry.getMetric() & 0xFFFFFFFF);
buf.writeInt(entry.getMetric());
}
// 根据版本选择目标地址
@ -49,5 +52,4 @@ public class RIPPacketEncoder extends MessageToMessageEncoder<RIPPacket> {
out.add(new DatagramPacket(buf, recipient));
}
}

View File

@ -1,186 +1,34 @@
package cn.x47.handle;
import cn.x47.model.RIPEntry;
import cn.x47.model.RIPPacket;
import cn.x47.service.RoutingTable;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
public class RIPServerHandler extends SimpleChannelInboundHandler<RIPPacket> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, RIPPacket msg) throws Exception {
InetSocketAddress senderAddress = msg.getSenderAddress();
byte version = msg.getVersion();
System.out.println(msg.toString());
// if (msg.getCommand() == 2) { // Response
// for (RIPEntry entry : msg.getEntries()) {
// // 更新本地路由表
// updateRoutingTable(entry, senderAddress, version);
// }
// } else if (msg.getCommand() == 1) { // Request
// // 处理请求发送响应包
// handleRequest(ctx, msg);
// }
}
private void handleRequest(ChannelHandlerContext ctx, RIPPacket requestPacket) throws Exception {
List<RIPEntry> requestEntries = requestPacket.getEntries();
byte version = requestPacket.getVersion();
boolean isGeneralRequest = false;
// 检查是否为一般请求
if (requestEntries.size() == 1) {
RIPEntry entry = requestEntries.get(0);
if (entry.getIpAddress().getHostAddress().equals("0.0.0.0") && entry.getMetric() == 16) {
isGeneralRequest = true;
if (msg.getCommand() == 2) { // Response
for (RIPEntry entry : msg.getEntries()) {
// 更新本地路由表
updateRoutingTable(entry);
}
}
RIPPacket responsePacket = new RIPPacket();
responsePacket.setCommand((byte) 2); // Response
responsePacket.setVersion(version); // 与请求的版本一致
responsePacket.setUnused((short) 0);
List<RIPEntry> responseEntries = new ArrayList<>();
if (isGeneralRequest) {
// 一般请求返回整个路由表
responseEntries.addAll(getAllRoutingEntries(version));
} else {
// 特定请求逐一处理请求的条目
for (RIPEntry requestEntry : requestEntries) {
RIPEntry route = getRoutingEntry(requestEntry.getIpAddress());
if (route != null) {
responseEntries.add(route);
} else {
// 如果没有该路由返回度量值为 16无限
RIPEntry unreachableEntry = new RIPEntry();
unreachableEntry.setAddressFamily(requestEntry.getAddressFamily());
unreachableEntry.setIpAddress(requestEntry.getIpAddress());
unreachableEntry.setMetric(16);
if (version == 2) {
unreachableEntry.setRouteTag((short) 0);
unreachableEntry.setSubnetMask(requestEntry.getSubnetMask());
unreachableEntry.setNextHop(InetAddress.getByName("0.0.0.0"));
}
responseEntries.add(unreachableEntry);
}
}
}
// 构建响应包
responsePacket.setEntries(responseEntries);
// 获取发送者的地址
InetSocketAddress recipient = requestPacket.getSenderAddress();
// 发送响应包
ByteBuf buf = ctx.alloc().buffer().order(ByteOrder.BIG_ENDIAN); // 确保使用大端序
encodeRIPPacket(responsePacket, buf);
DatagramPacket responseDatagram = new DatagramPacket(buf, recipient);
ctx.writeAndFlush(responseDatagram);
}
private void encodeRIPPacket(RIPPacket msg, ByteBuf buf) throws Exception {
// 编码命令和版本
buf.writeByte(msg.getCommand());
buf.writeByte(msg.getVersion());
buf.writeShort(0); // unused 字段
// 编码路由条目
for (RIPEntry entry : msg.getEntries()) {
buf.writeShort(entry.getAddressFamily());
if (msg.getVersion() == 2) {
buf.writeShort(entry.getRouteTag());
}
buf.writeBytes(entry.getIpAddress().getAddress());
if (msg.getVersion() == 2) {
buf.writeBytes(entry.getSubnetMask().getAddress());
buf.writeBytes(entry.getNextHop().getAddress());
}
buf.writeInt((int) (entry.getMetric() & 0xFFFFFFFFL));
} else if (msg.getCommand() == 1) { // Request
// 处理请求可能需要发送响应包
// ...
}
}
private List<RIPEntry> getAllRoutingEntries(byte version) throws Exception {
List<RIPEntry> entries = new ArrayList<>();
// 从路由表中获取所有的路由条目
for (RIPEntry route : RoutingTable.getInstance().getRoutes().values()) {
RIPEntry entry = new RIPEntry();
entry.setAddressFamily(route.getAddressFamily());
entry.setIpAddress(route.getIpAddress());
entry.setMetric(route.getMetric());
if (version == 2) {
entry.setRouteTag(route.getRouteTag());
entry.setSubnetMask(route.getSubnetMask());
entry.setNextHop(route.getNextHop());
}
entries.add(entry);
}
return entries;
}
private RIPEntry getRoutingEntry(InetAddress ipAddress) throws Exception {
RIPEntry route = RoutingTable.getInstance().getRoute(ipAddress);
if (route != null) {
RIPEntry entry = new RIPEntry();
entry.setAddressFamily(route.getAddressFamily());
entry.setIpAddress(route.getIpAddress());
entry.setMetric(route.getMetric());
entry.setRouteTag(route.getRouteTag());
entry.setSubnetMask(route.getSubnetMask());
entry.setNextHop(route.getNextHop());
return entry;
}
return null;
}
private void updateRoutingTable(RIPEntry entry, InetSocketAddress senderAddress, byte version) throws Exception {
if (version == 1) {
// 推断下一跳为发送者的地址
entry.setNextHop(senderAddress.getAddress());
// 根据 IP 地址类别推断子网掩码
InetAddress ipAddress = entry.getIpAddress();
byte[] addressBytes = ipAddress.getAddress();
int firstOctet = addressBytes[0] & 0xFF;
if (firstOctet >= 0 && firstOctet <= 127) {
// A 类地址
entry.setSubnetMask(InetAddress.getByName("255.0.0.0"));
} else if (firstOctet >= 128 && firstOctet <= 191) {
// B 类地址
entry.setSubnetMask(InetAddress.getByName("255.255.0.0"));
} else if (firstOctet >= 192 && firstOctet <= 223) {
// C 类地址
entry.setSubnetMask(InetAddress.getByName("255.255.255.0"));
} else {
// 非法地址忽略
System.out.println("Invalid IP address in RIP Entry: " + ipAddress.getHostAddress());
return;
}
}
private void updateRoutingTable(RIPEntry entry) {
// 实现路由表更新逻辑
// 这里只是示例实际需要处理路由添加更新超时等逻辑
RoutingTable.getInstance().updateRoute(entry);
System.out.println("Updated route: " + entry.getIpAddress().getHostAddress() +
" via " + entry.getNextHop().getHostAddress() +
" metric: " + entry.getMetric());
}
}

View File

@ -6,12 +6,13 @@ import java.net.InetAddress;
@Data
public class RIPEntry {
//
private short addressFamily;
private short routeTag; // RIP v2 特有
private InetAddress ipAddress;
private InetAddress subnetMask; // RIP v2 特有
private InetAddress nextHop; // RIP v2 特有
private long metric;
private int metric;
}

View File

@ -4,7 +4,6 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.net.InetSocketAddress;
import java.util.List;
@Data
@ -15,7 +14,6 @@ public class RIPPacket {
private byte version; // 1=RIP v1, 2=RIP v2
private short unused = 0; // 未使用设置为 0
private List<RIPEntry> entries;
private InetSocketAddress senderAddress;
// 添加构造方法和 Getter/Setter
public RIPPacket(byte command, byte version, List<RIPEntry> entries) {

View File

@ -4,12 +4,12 @@ package cn.x47.service;
import cn.x47.handle.RIPPacketEncoder;
import cn.x47.model.RIPPacket;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.nio.NioDatagramChannel;
public class RIPClient {

View File

@ -4,31 +4,75 @@ package cn.x47.service;
import cn.x47.handle.RIPPacketDecoder;
import cn.x47.handle.RIPServerHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.nio.NioDatagramChannel;
import java.net.*;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
public class RIPServer {
public void start() throws InterruptedException {
public void start() throws InterruptedException, UnknownHostException, SocketException {
NioEventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.option(ChannelOption.IP_MULTICAST_LOOP_DISABLED, true)
.handler(new ChannelInitializer<DatagramChannel>() {
@Override
protected void initChannel(DatagramChannel ch) throws Exception {
ch.pipeline().addLast(new RIPPacketDecoder(), new RIPServerHandler());
}
});
ChannelFuture future = b.bind(520).sync();
// 获取并加入组播组
NioDatagramChannel channel = (NioDatagramChannel) future.channel();
InetAddress multicastAddress = InetAddress.getByName("224.0.0.9"); // 替换为你的组播地址
// 自动获取网络接口并加入组播组
List<NetworkInterface> multicastInterfaces = getMulticastInterfaces();
for (NetworkInterface networkInterface : multicastInterfaces) {
channel.joinGroup(new InetSocketAddress(multicastAddress, 520), networkInterface).sync();
System.out.println("已在接口 " + networkInterface.getName() + " 上加入组播组");
}
System.out.println("监听器已启动,正在监听端口:" + 520);
future.channel().closeFuture().await();
} finally {
group.shutdownGracefully();
}
}
private List<NetworkInterface> getMulticastInterfaces() throws SocketException {
List<NetworkInterface> interfaces = new ArrayList<>();
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
while (networkInterfaces.hasMoreElements()) {
NetworkInterface networkInterface = networkInterfaces.nextElement();
if (networkInterface.isUp() && !networkInterface.isLoopback() && networkInterface.supportsMulticast()) {
// 检查是否有 IPv4 地址
Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
boolean hasIPv4 = false;
while (addresses.hasMoreElements()) {
InetAddress address = addresses.nextElement();
if (address instanceof Inet4Address) {
hasIPv4 = true;
break;
}
}
if (hasIPv4) {
interfaces.add(networkInterface);
}
}
}
return interfaces;
}
}

View File

@ -1,6 +1,7 @@
package cn.x47.service;
import cn.x47.model.RIPEntry;
import java.net.InetAddress;
@ -31,8 +32,4 @@ public class RoutingTable {
public Map<InetAddress, RIPEntry> getRoutes() {
return routes;
}
public RIPEntry getRoute(InetAddress ipAddress) {
return routes.get(ipAddress);
}
}

View File

@ -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<String, Integer> table;
// Stores local ip address
static String[] localIP;
// Stores it's neighbors
static ArrayList<String> neighbors;
//Stores destination and next hop
public static HashMap<String, String> 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<String, Integer> temp, String senderIP, Map<String, String> 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<String, Integer>, HashMap<String, String>> receiver;
// reads the input from the neighbor
receiver = (HashMap<HashMap<String, Integer>, HashMap<String, String>>) input.readObject();
HashMap<String, Integer> temp = (HashMap<String, Integer>) receiver.keySet().toArray()[0];
HashMap<String, String> tempHop = receiver.get(temp);
@SuppressWarnings("unused")
Iterator it = temp.entrySet().iterator();
Connection.updateTable(temp, connectionIP[1], tempHop);
HashMap<HashMap<String, Integer>, HashMap<String, String>> sender;
sender = new HashMap<HashMap<String, Integer>, HashMap<String, String>>();
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<String, Integer>, HashMap<String, String>> sender;
sender = new HashMap<HashMap<String, Integer>, HashMap<String, String>>();
sender.put(Connection.table, Connection.hop);
// sends updated cost and next hop table to the neighbor
output.writeObject(sender);
output.reset();
HashMap<HashMap<String, Integer>, HashMap<String, String>> receiver;
// reads updated cost and next hop table from neighbor
receiver = (HashMap<HashMap<String, Integer>, HashMap<String, String>>) input.readObject();
HashMap<String, Integer> temp = (HashMap<String, Integer>) receiver.keySet().toArray()[0];
HashMap<String, String> 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();
}
}
}

View File

@ -0,0 +1,85 @@
import java.net.InetAddress;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class RipV1PacketBuilder {
public static byte[] buildRipV1RequestPacket() throws IOException {
// 使用 ByteArrayOutputStream DataOutputStream 来构建数据包
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
// 1. Command (8比特) - 请求报文值为 1
dos.writeByte(1); // 请求报文
// 2. Version (8比特) - RIP v1值为 1
dos.writeByte(1); // RIP v1
// 3. Must be zero (16比特) - 保留字段必须为零
dos.writeShort(0); // 保留字段填充为零
// 4. Address Family Identifier (AFI) - 请求报文中为 0
dos.writeShort(0); // 请求报文的 AFI 0
// 5. IP Address (32比特) - 目标 IP 地址RIP 请求报文中通常为 0.0.0.0
InetAddress byName = InetAddress.getByName("200.0.2.0");
// 6. Metric (32比特) - 请求报文的 Metric 16表示不可达
dos.writeInt(16); // Metric = 16
// 转换成字节数组
return baos.toByteArray();
}
public static byte[] buildRipV1ResponsePacket() throws IOException {
// 使用 ByteArrayOutputStream DataOutputStream 来构建数据包
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
// 1. Command (8比特) - 响应报文值为 2
dos.writeByte(2); // 响应报文
// 2. Version (8比特) - RIP v1值为 1
dos.writeByte(1); // RIP v1
// 3. Must be zero (16比特) - 保留字段必须为零
dos.writeShort(0); // 保留字段填充为零
// 4. Address Family Identifier (AFI) - 请求报文中为 0
dos.writeShort(2); // 响应报文的 AFI 对于 IPv4 2
dos.writeShort(0);
// 5. IP Address (32比特) - 目标 IP 地址假设响应报文中为某个 IP
InetAddress byName = InetAddress.getByName("200.0.2.0");
printByteArray(byName.getAddress());
dos.write(byName.getAddress()); // 192.168.0.1IPv4 地址
// 6. Metric (32比特) - 路由的 Metric
dos.writeInt(1); // 假设 Metric 1
// 转换成字节数组
return baos.toByteArray();
}
public static void main(String[] args) throws IOException {
byte[] requestPacket = buildRipV1RequestPacket();
byte[] responsePacket = buildRipV1ResponsePacket();
System.out.println("RIP v1 Request Packet: ");
printByteArray(requestPacket);
System.out.println("RIP v1 Response Packet: ");
printByteArray(responsePacket);
}
// 打印字节数组的辅助函数
private static void printByteArray(byte[] byteArray) {
for (byte b : byteArray) {
System.out.printf("%02X ", b);
}
System.out.println();
}
}

View File

@ -0,0 +1,66 @@
import java.net.*;
import java.io.*;
public class RipV1Response {
public static void main(String[] args) {
try {
// 创建一个数据包
byte[] packet = createRipV1ResponsePacket();
// 创建一个UDP Socket
// DatagramSocket socket = new DatagramSocket();
// 创建一个UDP Socket并将其绑定到指定的 IP 地址
DatagramSocket socket = new DatagramSocket(null);
socket.bind(new InetSocketAddress(InetAddress.getByName("192.168.123.45"), 520)); // 使用特定的本地 IP 地址绑定端口
InetAddress address = InetAddress.getByName("224.0.0.9"); // RIPv1 默认的多播地址
// 创建一个DatagramPacket并发送
DatagramPacket sendPacket = new DatagramPacket(packet, packet.length, address, 520); // RIPv1 默认端口 520
socket.send(sendPacket);
System.out.println("RIP v1 Response packet sent!");
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// 构建RIP v1 响应数据包
public static byte[] createRipV1ResponsePacket() {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
try {
// 1. Command (8比特) - 响应报文 (Response)
dos.writeByte(2); // Command = 2表示响应报文
// 2. Version (8比特) - RIP版本号 (RIP-1)
dos.writeByte(1); // Version = 1RIP-1
// 3. Must be zero (16比特) - 保留字段必须为零
dos.writeShort(0); // 16比特的保留字段填充0
// 4. AFI (Address Family Identifier) (16比特) - 地址族标识符
dos.writeShort(2); // AFI = 2表示 IPv4 地址
dos.writeShort(0);
InetAddress byName = InetAddress.getByName("200.0.2.0");
// 5. IP Address (32比特) - 路由目标 IP 地址
dos.write(byName.getAddress()); // 192.168.0.1 IP 地址32位
dos.writeInt(0);
dos.writeInt(0);
// 6. Metric (32比特) - 路由开销
dos.writeInt(1); // Metric = 1表示一个跳数
} catch (IOException e) {
e.printStackTrace();
}
return bos.toByteArray();
}
}