通过控制台输入一段文字,输出MAC帧的2进制和16进制的字符串,主要是求FCS。这里只考虑单帧的情况,即只考虑输入数据在1字节~1500字节之间的情况,对于更长的数据暂不考虑。

1、MAC帧基本格式

表1 802.3标准的帧结构

前导码

帧前定界符

目的地址

源地址

长度字段

数据字段

校验字段

7B

1B

(6B)

(6B)

(2B)

46~1500字节

(4B)

具体内容参考:https://blog.csdn.net/icxiaoge/article/details/83420269

2、内容

目的地址:8000FF602CDC

源地址:8000FE853A5F

生成多项式:

3、程序思路

  1. 目的地址和源地址是已知的,由于计算CRC检验是2进制形式,可写函数hexToBinary(),将目的地址和源地址转换成2进制

  2. 右生成多项式得到用于CRC检验的除数p为:100000100110000010001110110110111

  3. 数据字段用ASCII编码,写函数dataToBinaryString()将数据转换成2进制字符串

  4. 长度字段由首部尾部18字节与数据字段长度(46字节~1500字节)和的2进制串

  5. 将目的地址、源地址、长度字段、数据字段组成MAC帧的前部分

  6. 利用得到的MAC帧前部分,用函数solveFcs()求出FCS

4、代码

主类MacFrameEncapsulation.java如下:

/*
* 文件内容:MAC帧封装
* 文件目标:输入一段不超过1500个字节的数据,输出封装后的MAC帧,
* MAC帧包含目的地址、源地址、长度/类型、数据,FCS 共5部分
* 各部分有单独输出显示,输出为2进制和16进制
* 时间:2018-11-15
* 作者:wowpH
*/ import java.util.Scanner; public class MacFrameEncapsulation { private int LENGTH_FIELD_BYTES = 2; // 长度字段长度为2 bytes
private int MIN_DATA_BYTES_LENGTH = 46; // 数据字段最小长度46 bytes
private int MIN_DATA_BITS_LENGTH = 368; // 数据字段最小长度368 bits
private int MAX_DATA_BYTES_LENGTH = 1500; // 数据字段最大长度1500 bytes
private int FCS_BITS_LENGTH = 32; // FCS长度(bit)
private String DESTINATION_ADDRESS = "8000FF602CDC"; // 目的地址
private String SOURCE_ADDRESS = "8000FE853A5F"; // 源地址
private String DIVISOR_P = "100000100110000010001110110110111"; // CRC检验的除数p
private String destinationBinaryAddress = ""; // 目的地址二进制
private String sourceBinaryAddress = ""; // 源地址二进制
private String lengthField = ""; // 长度字段2进制,2 bytes
private String data = ""; // 输入的数据部分
private String dataBinary = ""; // 输入的数据部分的2进制
private String fcs = ""; // CRC检验的FCS二进制
private String mac = ""; // MAC帧,包含目的地址、源地址、长度字段、数据字段,FCS共5部分
private String macHex = ""; // MAC帧16进制串
private String fcsHex = ""; // FCS十六进制串
// MAC帧初始长度(byte)为目的地址长度(6bytes)+源地址长度(6bytes)+长度字段(2bytes)+FCS长度(4bytes)
private int macByteLength = 18;
// 4位的二进制数串,0-15
String[] FOUR_BIT_BINARY_TABLE = {
"0000", "0001", "0010", "0011",
"0100", "0101", "0110", "0111",
"1000", "1001", "1010", "1011",
"1100", "1101", "1110", "1111"
}; // 开始
void begin() {
this.input();
this.dealWithDestinationAddress();
this.dealWithSourceAddress();
this.dealWithData();
this.dealWithLengthField();
this.mac += this.lengthField; // 将长度字段添加到MAC帧
this.mac += this.dataBinary; // 将数据字段添加到MAC帧
this.dealWithFcs();
this.dealWithMac();
}
// 输入数据
private void input() {
Scanner in = new Scanner(System.in);
String data = "";
while(data.equals("")) {
System.out.println("请输入传输的数据:");
data = in.nextLine();
this.data = data;
}
System.out.println("---------------------------------------------------------");
in.close();
}
// 显示信息
void output() {
System.out.println("MAC帧(2进制)为:");
System.out.println(this.mac);
System.out.println("目的地址为:");
System.out.println(this.destinationBinaryAddress);
System.out.println("源地址为:");
System.out.println(this.sourceBinaryAddress);
System.out.println("长度/类型(2进制)为:");
System.out.println(this.lengthField);
System.out.println("数据为:");
System.out.println(this.dataBinary);
System.out.println("FCS(2进制)为:");
System.out.println(this.fcs);
System.out.println("MAC帧(16进制)为:");
System.out.println(this.macHex);
System.out.println("FCS(16进制)为:");
System.out.println(this.fcsHex);
System.out.println("---------------------------------------------------------");
}
// 处理目的地址
private void dealWithDestinationAddress() {
this.destinationBinaryAddress = this.hexToBinary(this.DESTINATION_ADDRESS);
this.mac += this.destinationBinaryAddress; // 将目的地址(2进制)添加到MAC帧
}
// 处理源地址
private void dealWithSourceAddress() {
this.sourceBinaryAddress = this.hexToBinary(this.SOURCE_ADDRESS);
this.mac += this.sourceBinaryAddress; // 将源地址(2进制)添加到MAC帧
}
// 处理传输数据
private void dealWithData() {
int dataByteLength = 0; // 数据长度(byte)
this.dataBinary = this.dataToBinaryString(data);
dataByteLength = this.dataBinary.length() / 8;
if(dataByteLength < this.MIN_DATA_BYTES_LENGTH) {
this.dataBinary = this.fillZero(this.dataBinary, this.MIN_DATA_BITS_LENGTH, false);
dataByteLength = this.MIN_DATA_BYTES_LENGTH;
} else if(dataByteLength > this.MAX_DATA_BYTES_LENGTH) {
System.out.println("输入的数据超过范围!");
System.exit(0);
}
this.macByteLength += dataByteLength;
}
// 处理长度字段
private void dealWithLengthField() {
this.lengthField = Integer.toBinaryString(this.macByteLength);
this.lengthField = this.fillZero(this.lengthField, this.LENGTH_FIELD_BYTES * 8, true);
}
// 处理FCS
private void dealWithFcs() {
String dividend = this.fillZero(this.mac, this.mac.length() + this.FCS_BITS_LENGTH, false);
this.fcs = this.solveFcs(dividend, this.DIVISOR_P);
this.fcsHex = this.binaryToHex(this.fcs);
this.mac += this.fcs;
}
// 处理MAC帧
private void dealWithMac() {
this.macHex = this.binaryToHex(this.mac);
}
/* @return String 返回求解到的FCS串
* @param dividend 被除数,二进制
* @param divisor 除数,二进制
*/
private String solveFcs(String dividend, String divisor) {
String fcs = "";
char[] dividendArray = dividend.toCharArray();
char[] divisorArray = divisor.toCharArray();
// 指向被除数中用于当前运算的数据的首部和尾部,长度和除数相同
int head = 0; // 指向头部下标,第一次是0
int tail = head + divisor.length() - 1; // 尾部下标,第一次是32
int i;
while(tail < dividend.length()) {
if('1' == dividendArray[head]) {
for(i = head; i <= tail; ++i) {
if(dividendArray[i] == divisorArray[i - head]) {
dividendArray[i] = '0';
} else {
dividendArray[i] = '1';
}
}
}
++head;
++tail;
}
for(i = head; i < dividendArray.length; ++i) {
fcs += dividendArray[i];
}
return fcs;
}
/* @return String 二进制字符串
* @param data 字符串
* 将字符串转换成二进制字符串,通过ASCII转换
*/
private String dataToBinaryString(String data) {
char[] stringArray = data.toCharArray();
String result = "";
String oneBit = "";
for (int i = 0; i < stringArray.length; ++i) {
oneBit = Integer.toBinaryString(stringArray[i]);
oneBit = this.fillZero(oneBit, 8, true);
result += oneBit;
}
return result;
}
/* @return String 填充0之后的二进制串
* @param data 需要填充0的二进制串
* @param finalBitLength 填充0后的长度(位)
* @param way 填充0。way=true 首部填充0,way=false 尾部填充0
*/
private String fillZero(String data, int finalBitLength, boolean way) {
String result = "";
for(int i = data.length(); i < finalBitLength; ++i) {
result += '0';
}
if(true == way) {
result += data;
} else {
result = data + result;
}
return result;
}
/* @return String 返回转换后的二进制串
* @param hex 要转换的十六进制串
*/
private String hexToBinary(String hex) {
String binary = "";
int hexBitLength = hex.length();
for(int i = 0; i < hexBitLength; ++i) {
if(hex.charAt(i) >= '0' && hex.charAt(i) <= '9') {
binary += this.FOUR_BIT_BINARY_TABLE[hex.charAt(i) - '0'];
} else if(hex.charAt(i) >= 'a' && hex.charAt(i) <= 'z') {
binary += this.FOUR_BIT_BINARY_TABLE[hex.charAt(i) - 'a' + 10];
} else if(hex.charAt(i) >= 'A' && hex.charAt(i) <= 'Z') {
binary += this.FOUR_BIT_BINARY_TABLE[hex.charAt(i) - 'A' + 10];
}
}
return binary;
}
/* @return String 16进制串
* @param binary 需要转换成16进制的2进制串
*/
private String binaryToHex(String binary) {
String hex = "";
String fourBits = "";
int oneBit = 0;
int length = binary.length() / 4;
for(int i = 0; i < length; ++i) {
fourBits = binary.substring(0, 4);
oneBit = Integer.parseInt(fourBits, 2);
hex += Integer.toHexString(oneBit);
binary = binary.substring(4);
}
return hex;
}
}

测试类Test.java代码如下:

public class Test {
public static void main(String[] args) {
MacFrameEncapsulation f = new MacFrameEncapsulation();
f.begin();
f.output();
}
}

5、截图

MAC帧封装的更多相关文章

  1. LB(Load balance)负载均衡集群--{LVS-[NAT+DR]单实例实验+LVS+keeplived实验} 菜鸟入门级

    LB(Load balance)负载均衡集群 LVS-[NAT+DR]单实例实验 LVS+keeplived实验 LVS是Linux Virtual Server的简写,意即Linux虚拟服务器,是一 ...

  2. LVS-DR工作原理

    我们都知道LVS有LVS-DR,LVS-NAT,LVS-TUN三种模式,其中DR模式意为Direct Routing(直接路由).对于LVS-DR,你到底了解到什么程度?本文通过一个实例场景,详细介绍 ...

  3. 2. LVS/DR 配置

    平台:RedHat Enterprise Linux centos6.3       ipvsadm             ipvs 1.DR模型 DR模型:直接路由模型,每个Real Server ...

  4. LVS实战1

    (一).NAT模式:NAT模型:地址转换类型,主要是做地址转换,类似于iptables的DNAT类型,它通过多目标地址转换,来实现负载均衡:特点和要求: 1.LVS(Director)上面需要双网卡: ...

  5. 基于FPGA的以太网开发

    基于FPGA的以太网开发,在调试过的FPGA玩家开来,其实算不上很难的技术!但是如果只是菜鸟级别的选手,没有调试过的话,就有些头疼了!早在自己在实习的时候,就接触到XAUI(万兆以太网口)接口,但是由 ...

  6. 计算机网络中的帧封装(C实现)

    这段时间开始复习计算机网络,看到帧封装这一节,结合以前的课程设计,就用C写了个帧封装的程序,说实话C学的确实不怎么样,实现的时候对于文件操作那部分查了好多资料,下面说说帧封装是啥情况. 学过计算机网络 ...

  7. 转发表(MAC表)、ARP表、路由表总结

    原文:https://cloud.tencent.com/developer/article/1173761 转发表(MAC表).ARP表.路由表总结 我是东东东   发表于我是东东强订阅 1.5K ...

  8. 计算机网络参考模型,IP地址及MAC地址查看方法,数据包封装过程

    分层思想 首先,计算机网络参考模型,是基于分层思想而出现的.分层思想,就是将复杂流程分解为几个功能单一的子过程. 优点: 可以让整个流程更加清晰, 让复杂问题简单化, 更容易发现问题,并真对性的解决问 ...

  9. 总结:Mac前端开发环境的搭建(配置)

    新年新气象,在2016年的第一天,我入手了人生中第一台自己的电脑(大一时好友赠送的电脑在一次无意中烧坏了主板,此后便不断借用别人的或者网站的).macbook air,身上已无分文...接下来半年的房 ...

随机推荐

  1. python技巧获取26个英语字母

    import string string.ascii_uppercase # 获取26个大写字母 string.ascii_lowercase # 获取26个小写字母 string.ascii_let ...

  2. ubuntu进程监视器htop 清除黄色内存(缓存)

    大意是:对于CPU显示条: 蓝色为:低优先级的线程 绿色为:正常优先级线程 红色为:内核线程 对于内存显示条: 蓝色为:缓冲区(buffers) 绿色为:已使用的内存 (橘)黄色为:高速缓存(cach ...

  3. python 日期

    python datetime库使用和时间加减计算  来自:https://www.cnblogs.com/linkenpark/p/8079337.html datetime库使用 一.操作当前时间 ...

  4. JVM内存空间划分与作用

    虚拟机栈:Stack Fame 栈桢 程序计数器(Program Counter): 本地方法栈:主要用于处理本地方法 堆(Heap): JVM管理的最大一块内存空间 方法区(Method Area) ...

  5. ActiveMQ参数异常 “Invalid broker URI”

    某次启动项目报错,提示ActiveMQ参数异常 该参数的值配置如下 跟踪读取配置的代码如下,可以看到读取我配置的key为xmq.actmq.connection.url.forSend的对应值,赋值到 ...

  6. git之删除untrack files

    退回版本 git reset --hard commit_id //不保留未提交的修改 git reset --soft commit_id //默认方式,保留未提交的修改 撤除本地没有提交的修改 g ...

  7. Maltego更新到4.2.6

    Maltego更新到4.2.6   此次更新包含以下两处修改: (1)在服务管理中,允许用户修改OAuth回调协议的端口. (2)修复启动画面溢出错误.

  8. 让remix使用本地文件系统

    让remix使用本地文件系统   转:https://blog.csdn.net/platocnet/article/details/83376792 1. 测试发现使用npm命令安装相关环境不成功, ...

  9. Python写入csv文件示例

    import csv header = ['City', 'AQI', 'PM2.5/1h', 'PM10/1h', 'CO/1h', 'NO2/1h', 'O3/1h', 'O3/8h', 'SO2 ...

  10. 从0开始学爬虫7之BeautifulSoup模块的简单介绍

    参考文档: https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/ # 安装 beautifulsoup4 (pytools) D:\pyt ...