交换机在操作过程当中会不断的收集信息去创建它本身的一个地址表,这个表相当简单,它说明了某个MAC地址是在哪个端口上被发现的,所以当交换机收到一个TCP/IP 数据包时,它便会查看该数据包的目的MAC地址,核对自己的地址表以确认应该从哪个端口把数据包发出去。
我们假设一个以太网交换机有1、2、3、4,共4个接口,每个接口都分别连接了一台计算机,他们的MAC地址分别是A、B、C和D。在最开始的时候,交换机的交换表是空的,如下表。
接口号 | Mac地址 |
假如A向B发送了一帧,从接口1进入交换机,交换机收到这一帧之后会先查找交换表,不过很显然表是空的,交换机查不到应该从哪个接口转发这个帧(就是找不到目的地址为B的表项)。那么接下来,交换机就会把这个帧的源地址A和接口1写入交换表中,并向除了接口1之外的所有接口广播这个帧。那么现在交换表就变成了下面这个样子:
接口号 | Mac地址 |
1 | A |
那么这样一来,不论交换机的哪个接口收到目的地址是A的帧,都只要把这个帧转发到接口1,因为既然A发送的帧能从接口1进入交换机,那么交换机自然也能从接口1找到A。
上面我们说交换机会向除接口1之外的所有接口广播A发出的那一帧,C跟D收到之后将会丢弃这个帧,因为目的地址与他们的MAC地址不符,只有B会收下这一帧。这种机制也称为过滤。
那么经过一段时间,交换机会把所有发送过数据的主机的MAC地址与对应接口号记录下来,这样交换表中的表项就齐全了,要转发给任何一台主机的帧都能很快的在交换表中找到相对应的转发接口。
使用Java模拟交换机自学习的算法:
import java.util.*;
import java.util.regex.Pattern;
/*
交换机自学习算法:假定有n台计算机,交换机mac表初始为空,在多次收发帧后,建立Mac表
*/
class Com {
int port;
String sourceMac;
String targetMac;
Com(int port,String sourceMac,String targetMac) {
this.port = port;
this.sourceMac = sourceMac;
this.targetMac = targetMac;
}
}
public class Demo {
public static void main(String[] args) {
/**
* @formatter 格式化输出字符串
* @dataList 存放每个帧对象的队列,可有可无
* @macList 存放Mac地址表的哈希表,因为哈希表的键唯一特性,就不用对输入的数据做端口号去重,还能自动实现Mac表中Mac地址的更新
*/
Scanner scanner = new Scanner(System.in);
Formatter formatter = new Formatter(System.out);
ArrayList<Com> dataList = new ArrayList<Com>(); //帧信息组
Map<Integer,String> macList = new HashMap<>(); //Mac表
final String regex = "([A-Fa-f0-9]{2}-){5}[A-Fa-f0-9]{2}";
// 输入帧信息
for (;;) {
System.out.println("————请输入帧信息————");
System.out.print("接口号:");
int port = scanner.nextInt();
System.out.print("源mac地址:");
String smac = scanner.next();
System.out.print("目标地址:");
String tmac = scanner.next();
// 使用正则表达式,校验是否为Mac地址
if (!(Pattern.matches(regex,smac) && Pattern.matches(regex,tmac))) {
System.out.println("请输入正确的Mac地址!");
continue;
}
dataList.add(new Com(port, smac, tmac));
System.out.print("是否继续(Y/N):");
// 判断接口及mac信息是否在mac表中,不在则添加
if (!macList.containsValue(smac)) {
macList.put(port, smac);
}
if (!scanner.next().equals("Y")) break;
}
// 输出mac表
formatter.format("%-6s %-15s \n","接口号","Mac地址");
macList.forEach((k,v) -> formatter.format("%-6s %-15s \n",k,v));
}
}