zoukankan      html  css  js  c++  java
  • 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、截图

    截图

  • 相关阅读:
    pat乙级1034
    getline()读入一整行
    c++ 输入split
    13.缓存、三级缓存、内存溢出、AsyncTask
    12、json、GridView、缓存
    11.webview、shareSDK
    10.下拉刷新、加载更多、标记已读、轮播条、缓存
    9.indicate、xutils、json
    8.滑动事件处理
    7.ViewPagerIndicator
  • 原文地址:https://www.cnblogs.com/wowpH/p/11060857.html
Copyright © 2011-2022 走看看