在可变位宽二进制块

时间:2015-04-23 11:17:54

标签: php encoding bit-manipulation binary-data

我正在尝试为网络化个人项目中的协议构建一个可变位宽二进制编码器/解码器我正在设计......而我的愚蠢大脑已经完全卡住了如何掌握变量 - 位宽二进制编码/解码。我现在已经盯着同样的~18 SLOC大约四天了,我仍然感到完全超出了我的深度。我觉得我应该能够理解这一点,但不幸的是,当我试图跟踪不同的数字关系时,我的大脑会随机出现:(

理论上,我想做的事情非常简单。我声明了一个位宽列表,以及我想要存储在该位宽内的值,如下所示:

[10 bits]: 1013
[1  bit ]: 1
[2  bits]: 3
[19 bits]: 51209

考虑到位宽,这些值将逐步排序为二进制字符串,如下所示:

               1 bit
               | 2 bits  
               | ||  
  /-10 bits--\ | \/ /------ 19 bits ------\  
  12345678  12 3 45 678  12345678  12345678  
  11111101  01 1 11 000  11001000  00001001  
  \----------/ | \/ \---------------------/
      1012     1  3          51209

以上粗体的比特流是我传输的内容:

11111101  253  FD
01111000  120  78
11001000  200  C8
00001001    9  09

在另一端,我将列表{10, 1, 2, 19}(顶部表示的位宽集)映射到我收到的字节序列,然后给我留下原始的值集I想要传播。

虽然这主要是一个通用的算法问题,并且任何特定语言的语义都可以说无关紧要,但我应该提到我使用PHP来实现这一点 - 而我之所以如此困难,部分原因在于我试图弄清楚如何避免诉诸字符串操作,PHP似乎过于倾向于鼓励人们偏爱正确的数字处理。但是,这个功能(希望)能够以2到3位Mbps的速度处理数据,我希望这些例程尽可能快。 (顺便说一句,我使用其他语言,但PHP是我最了解的那个> _>)

我确实理解二进制的基础知识,我应该强调我确实有一个工作编码器,我认为(它向后输出二进制数据) - 但我不知道我在这里做了什么。我不是要问"我该怎么写这个功能,"我问'我做什么的结构力学是什么,我怎么做到这一点。"

我还应该注意,这个问题不是一个伪装的家庭作业;它是个人软件项目中的网络库组件我希望能够教会我关于网络,事件处理和并发的知识。希望我能掌握我需要实施的所有其他事情......大声笑

1 个答案:

答案 0 :(得分:2)

为了给你一个小小的起点,这样的二进制解码器/编码器在这里是一个例子:

那么现在背后的概念是什么?

非常简单我遍历您要发送的每个数据并将它们拆分为单个字节。举个例子:

data:    1013
bitMask:   10

所以我首先计算发送它需要多少字节。这里将是2字节,每字节8位。

经过所有的准备和计算,可以直接逐字节地发送所有数据!因此,如果我们从上面举例,这看起来像这样:

data:    1013  -> 0000'0011 1111'0101
bitMask:   10

total amount of bytes: 2
1. byte = 1111'0101
2. byte = 0000'0011

因此,在发送数据时(此处在浏览器中输出),您正在反向显示数据!因为当你收到它时,你正在改变它,你会得到正确的结果!

<?php

    class binaryCoder {

        /* Properties */
        public $data;  // <-- save/receive data into this property
        public $bitMask = [];
        private $byteCount = 0x00;

        /* Constructor */
        public function __construct() {


        }

        /* Methods */
        public function writeData(array $data, array $bitMask) {

            $this->data = $data;
            $this->bitMask = $bitMask;
            $this->byteCount = array_reduce($this->bitMask, function($byteCount, $bits){
                return $byteCount + ceil($bits/8);
            }, 0x00);


            foreach(array_combine($this->bitMask, $this->data) as $mask => $data) {
                for($byteCounter = 0; $byteCounter < ceil($mask/8); $byteCounter++) {
                    $this->writeByte($data >> ($byteCounter*8));
                }
            }

        }

        public function readData(array $bitMask) {
            $this->bitMask = $bitMask;
            $byte = 0x00;


            foreach($this->bitMask as $key => $mask) {
                $message[$key] = "";
                for($byteCounter = 0; $byteCounter < ceil($mask/8); $byteCounter++, $byte++) {
                    $message[$key] = sprintf("%08d", $this->readByte($byte*8)) . $message[$key];
                }
            }

            $message = array_map("bindec", $message);
            print_r($message);

        }

        private function writeByte($byte) {
            for($bitCount = 0; $bitCount < 8; $bitCount++) {
                $this->writeBit((bool)($byte & (1 << $bitCount)));
            }
        }

        private function readByte($bytePosition) {
            $byte = 0x00;

            for($bitCount = 0; $bitCount < 8; $bitCount++) {
                $byte |= (int)$this->readBit($bytePosition+$bitCount) << $bitCount;
            }
            return decbin($byte);
        }

        private function writeBit($bit) {
            echo ($bit?1:0);  // --> send/write data to dest. (Note it's reversed!)
        }

        private function readBit($bit) {
            return $this->data[$bit];
        }


    }


    /* Testing */
    $binaryTransmitter = new binaryCoder();
    $binaryTransmitter->writeData([1013, 1, 3, 51209], [10, 1, 2, 19]);
    $binaryTransmitter->data = "10101111110000001000000011000000100100000001001100000000";  //received data 
    $binaryTransmitter->readData([10, 1, 2, 19]);

?>

输出:

10101111110000001000000011000000100100000001001100000000 //note output here is reversed!
Array ( [0] => 1013 [1] => 1 [2] => 3 [3] => 51209 )