Перевод Int32 в ushort и обратно

Я пытаюсь разработать систему для упаковки целочисленных значений больше 65535 в ushort. Позволь мне объяснить.

У нас есть система, которая генерирует значения Int32 с использованием столбца IDENTITY из SQL Server и ограничена производственным клиентским API, который переполняет наши идентификаторы Int32 на ushorts. К счастью, у клиента есть только около 20 экземпляров вещей с этими идентификаторами - назовем их пакетами - в любой момент времени, и ему нужно только, чтобы они были уникальными среди локальных братьев и сестер. Общепринятое решение - перевести наши идентификаторы Int32 в ushorts (и нет, я не имею в виду кастинг, я имею в виду перевод) перед их передачей клиенту, однако в этом подходе есть зазубрины:

  1. Некоторые идентификаторы менее 65535 могут все еще использоваться на данном клиенте в любое время из-за того, что срок их действия не истек.
  2. У нас не может быть никаких конфликтов идентификаторов - то есть, если пакет с идентификатором 1 переходит к клиенту, алгоритм, который отслеживает, сколько раз 65535 удаляется из Int32, чтобы сделать ushort при применении к 65536, также приведет к 1, что приведет к конфликту.
  3. Мы должны иметь возможность реконструировать ushort в Int32 по возвращении.

Для решения этой проблемы у нас есть одно поле байта со знаком, которое передается нам эхом и дает нам 127 значений для игры (на самом деле 117, потому что мы используем 0–9 для чего-то еще). В дальнейшем я буду называть это "байтовым полем".

Мы обсудили три различных процедуры перевода:

  1. Мультипликативный: сохраните в поле байтов, сколько раз мы удаляем 65535 из нашего Int32, чтобы сделать ushort. У этого есть проблемы со столкновением, как описано выше.
  2. Сериализованное состояние сеанса: для каждого клиента сгенерируйте идентификатор сеанса на основе фактов об этом клиенте. Затем сохраните таблицу преобразования 1: 1, начиная с 1 до количества доставленных пакетов, чтобы, когда клиент снова обращается к нашему серверу, инвентарь пакетов может быть преобразован обратно в их известные идентификаторы базы данных. У этого есть проблемы с накладными расходами, поскольку мы будем поддерживать сериализованное состояние сеанса в базе данных, и мы хотим поддерживать от сотен до тысяч транзакций в секунду.
  3. Разнообразный алгоритмический подход, в котором байтовое поле является идентификатором алгоритма преобразования, который принимает Int32 и преобразует его в ushort. Очевидно, что многие из них будут простыми мультипликативными (чтобы увеличить наш потолок идентификаторов, которые мы можем преобразовать), но некоторые из них должны быть мультипликативными с меньшей границей (например, 32768) с числом, добавляемым / вычитаемым из, чтобы максимально приблизиться к число, которое может быть гарантировано уникальным среди братьев и сестер. Этот подход требует интенсивного использования процессора, но должен позволить нам избежать коллизий, оставаясь при этом масштабируемым (хотя при таком подходе у нас есть ограниченный потолок, который не будет достигнут до тех пор, пока проблема ushort не исчезнет сама по себе из-за обновлений).

Итак, мой вопрос: есть ли лучший способ, чем мои подходы, описанные выше, и если нет, то что я должен искать с точки зрения алгоритмов (для подхода # 3) для генерации числа от 1 до 65535, когда заданное число больше, чем 0 а не должно быть одностороннего хеширования?

Уточнение: проблема не в том, что потолок ushort является самой большой проблемой, а в том, что клиентский API использует ushort, поэтому я не могу объединить байтовое поле на клиенте для получения больших значений (клиентский API не подлежит обновлению, но в конечном итоге прекратит свое существование ).

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
694
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Насколько "больше" 65535 вам нужно? Вы всегда можете просто добавить несколько битов из своего «байтового поля» в качестве старших битов идентификатора. Всего 2 бита дадут вам 262 143, 3 бита - 524 287.

Я могу придумать еще несколько вариантов:

В базе данных глобально меньше 65536 записей? Если это так, то вы можете поддерживать таблицу сопоставления, которая не связана с состоянием сеанса, но является постоянной частью приложения.

Неужели большинство записей в индексах меньше, скажем, 50 000? В этом случае вы можете напрямую сопоставить такие значения и использовать карту, связанную с сеансом, для оставшихся.

Если сохранение таких данных сеанса является проблемой и количество клиентов достаточно мало, вы можете включить привязку клиент / сеанс и сохранить карту локально для сервера.

Если это не веб-приложение, вы можете поддерживать карту на самом клиенте.

Я не вижу никакого алгоритмического способа избежать столкновений - я подозреваю, что вы всегда можете найти примеры, которые бы столкнулись.

Ответ принят как подходящий

Относительно подхода 2:

Ваш второй подход в значительной степени зависит от того, как работает NAT. Каждый клиент TCP / UDP в локальной сети имеет до 65535 используемых портов (кроме порта 0) и частный IP-адрес. Маршрутизатор знает только один общедоступный IP-адрес. Поскольку два клиента могут иметь порт источника 300, он не может просто заменить частный IP-адрес на общедоступный, что может вызвать коллизии. Таким образом, он заменяет IP и «транслирует» порт (NAT: сетевой адрес Перевод). По возвращении он переводит порт обратно и снова заменяет общедоступный частным IP-адресом, прежде чем пересылать пакет обратно. Вы бы больше ничего не делали. Однако маршрутизаторы хранят эту информацию в памяти - и они не слишком медленные при выполнении NAT (компании с сотнями компьютеров иногда подключаются к Интернету через NAT, и в большинстве случаев замедление практически не заметно). Вы говорите, что хотите проводить до тысячи транзакций в секунду, но сколько клиентов будет? Поскольку это в основном будет определять размер памяти, необходимой для резервного копирования сопоставлений. Если клиентов не слишком много, вы можете сохранить сопоставление с отсортированной таблицей в памяти, в этом случае скорость будет наименьшей проблемой (таблица становится больше, а на сервере не хватает памяти).

Что мне немного непонятно, так это то, что вы однажды сказали

Fortunately the client only has about 20 or so instances of things with these IDs - let's call them packages - at any given time and it only needs to have them unique amongst local siblings.

но потом ты говоришь

Some IDs less than 65535 may still be in play on a given client at any time due to non-expiration.

Думаю, под вторым утверждением вы, вероятно, имели в виду, что если клиент запрашивает идентификатор 65536, у него все еще могут быть идентификаторы ниже 65535, а они могут быть даже (скажем) 20. Дело не в том, что клиент обрабатывает идентификаторы в прямой порядок, правда? Таким образом, вы не можете сказать, что только потому, что он теперь запросил 65536, он может иметь несколько меньшие значения, но, конечно, не в диапазоне 1-1000, верно? На самом деле он может содержать ссылку на 20, 90, 2005 и 41238 и по-прежнему превышать 65535, вы это имели в виду?

Мне лично ваш второй подход нравится больше, чем третий, так как в любом случае легче избежать столкновения, а обратный перевод числа - простая и простая операция. Хотя сомневаюсь, что ваш третий подход может работать в долгосрочной перспективе. Хорошо, у вас может быть байт для хранения того, как часто вы вычитали 2 ^ 16 из числа. Однако вы можете вычесть только 117 * 2 ^ 16 как самые большие числа. Что вы будете делать, если цифры превысят это число? Используя другой алгоритм, который не вычитает, но что делает? Делить? Биты сдвига? В этом случае вы теряете детализацию, это означает, что этот алгоритм больше не может использовать ударить для любого возможного числа (он будет делать большие скачки). Если бы было так просто применить волшебную функцию трансляции к 32 битам, чтобы сделать из нее 16 бит (+ один дополнительный байт), а затем просто преобразовать ее обратно, угадайте, что каждый метод сжатия в этом мире использовал бы ее, как мог, нет независимо от того, каким было 32-битное число, всегда сжимайте его до 24 бит (16 бит + один байт). Это было бы волшебством. Невозможно упаковать 32 бита в 24 бита, а также упаковать всю логику, как преобразовать его обратно в него. Вам понадобится внешнее хранилище, что возвращает нас ко второму подходу. Это единственный подход, который будет работать, и он будет работать для каждого числа в 32-битном диапазоне чисел.

Принято удалить это из списка неотвеченных вопросов, и это хорошее объяснение решения проблемы.

cfeduke 03.11.2008 08:37

Похоже, вы путаете PAT или NAPT и NAT в своем сообщении. NAT не транслирует порт, он транслирует адрес, в то время как PAT и NAPT транслируют и адрес, и порт.

Fraser 26.11.2009 13:31

@Fraser: Не придирайтесь, пожалуйста. Основная цель NAT состоит в том, чтобы сопоставить несколько внутренних частных IP-адресов с одним общедоступным, и это невозможно, если вы также не выполняете PAT (или два хоста никогда не общаются с одним и тем же хостом в Интернете, используя одну и ту же услугу. - будет сложно обеспечить доступ к гуглу, бац); PAT в основном не существующий термин в сетевом бизнесе. См. Также страницу Википедии о NAT; они только быстро упоминают PAT, говорят, вы также можете просто сказать NAT для этого и использовать только NAT для описания всех видов NAT.

Mecki 27.11.2009 21:20

Другие вопросы по теме