Я пытаюсь создать двоичный кодер / декодер с переменной битовой шириной для протокола в персональном сетевом проекте, который я разрабатываю … и мой тупой мозг полностью запутался в том, как понять двоичное кодирование / декодирование с переменной битовой пропускной способностью. Я смотрю на тот же ~ 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}
(набор битовых полос обозначен вверху) в зависимости от последовательности байтов, которые я получил, что оставляет мне исходный набор значений, которые я хотел передать.
Хотя это, в основном, общий алгоритмический вопрос, и семантика любого конкретного языка, возможно, не имеет значения, я должен упомянуть, что я использую PHP для этого — и одна из причин, по которой я так застрял, состоит в том, что я пытаюсь решить как избежать обращения к строковым манипуляциям, которые PHP, похоже, одержимо склоняет к тому, чтобы поощрять предпочтение перед правильной числовой обработкой. Однако эта функция (надеюсь) будет обрабатывать данные на скоростях от 2 до 3 цифр-Мбит / с, и я хочу, чтобы подпрограммы были максимально быстрыми. (Кстати, я бы использовал другой язык, но PHP я знаю больше всего> _>)
Я понимаю основы двоичного кода, и я должен подчеркнуть, что у меня действительно есть работающий кодер, я думаю (он выводит двоичные данные в обратном направлении) — но я понятия не имею, что я здесь делаю. Я не спрашиваю «как мне написать эту функцию», я спрашиваю «какова структурная механика того, что я делаю, и как мне вообще это понять».
Я должен также отметить, что эта проблема не является замаскированным домашним заданием; это для компонента сетевой библиотеки в персональном программном проекте, который я проектирую, который, я надеюсь, научит меня сетевым технологиям, обработке событий и параллелизму. Надеюсь, я смогу понять все другие вещи, которые мне нужно будет реализовать … LOL
Чтобы дать вам небольшую отправную точку, как такой двоичный декодер / кодировщик может выглядеть вот как пример:
Итак, что же это за концепция?
Довольно просто я перебираю все данные, которые вы хотите отправить, и разделяю их на отдельные байты. Итак, в качестве примера:
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 )
Других решений пока нет …