MAC帧封装

通过控制台输入一段文字,输出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

生成多项式:{\color{Red}G(x)=x^{32}+x^{26}+x^{23}+x^{22}+x^{16}+x^{12}+x^{11}+x^{10}+x^{8}+x^{7}+x^{5}+x^{4}+x^{2}+x+1}

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、截图

截图

猜你喜欢

转载自blog.csdn.net/pfdvnah/article/details/84206749
mac