Если максимальное значение таймера ограничено и известно заранее, можно применить более эффективный метод — использовать массив под названием циклическое расписание (timing wheel) (илл. 6.54). Каждый слот соответствует одному тактовому импульсу. Текущее время, показанное на рисунке, — T = 4. Таймеры должны сработать через 3, 10 и 12 импульсов. Если новый таймер должен сработать через 7 импульсов, требуется сделать запись в слоте 11. Аналогично, если нужно отключить таймер, установленный на T + 10, нужно проверить список, начинающийся в слоте 14, и удалить соответствующую запись. Следует отметить, что массив на илл. 6.54 не может поддерживать таймеры за пределами T + 15.
Илл. 6.54. Циклическое расписание
Когда работает таймер, указатель текущего времени перемещается по циклическому расписанию вперед на один слот. Если запись, на которую он указывает, не нулевая, обрабатываются все таймеры этого списка. Многочисленные варианты этой концепции обсуждаются у Варгезе и Лаука (Varghese and Lauck, 1987).
6.7.7. Сжатие заголовков
Перейдем к вопросу о производительности беспроводных сетей и сетей других типов, где пропускная способность ограниченна. При уменьшении издержек, возникающих из-за программного обеспечения, портативные компьютеры будут работать эффективнее, но это не поможет улучшить производительность в тех случаях, когда проблемой являются сетевые каналы.
Чтобы эффективно использовать пропускную способность, заголовок протокола и пользовательские данные должны занимать как можно меньше битов. В случае пользовательских данных этого можно достичь путем компактного кодирования информации: к примеру, изображения лучше передавать в формате JPEG, а не в растровых форматах, а документы — в форматах со сжатием, таких как PDF. Также для этого необходимы механизмы кэширования прикладного уровня (например, кэш веб-страниц), уменьшающие число передач.
А что делать с заголовками протоколов? В беспроводных сетях на канальном уровне заголовки обычно занимают мало места, поскольку изначально рассчитаны на низкую пропускную способность. В сетях, ориентированных на установление соединения, пакеты имеют короткие идентификаторы соединения вместо длинных адресов. Но протоколы более высоких уровней (IP, TCP или UDP) универсальны для всех типов сетей, поэтому в них не используются компактные заголовки. На самом деле потоковая обработка, уменьшающая затраты на программное обеспечение, часто приводит к еще большему увеличению длины заголовка (например, в IPv6 используются более разреженные заголовки, чем в IPv4).
Заголовки более высоких уровней могут сильно влиять на производительность. Например, рассмотрим процесс передачи VoIP-данных через IP, UDP и RTP. Этим протоколам требуется заголовок длиной 40 байт (20 байт для IPv4, 8 — для UDP, 12 — для RTP). В случае IPv6 ситуация еще хуже: 60 байт, включая 40-байтный заголовок IPv6. Эти заголовки могут становиться еще длиннее, потребляя более половины пропускной способности.
Чтобы уменьшить пропускную способность, потребляемую заголовками высоких уровней, применяется сжатие заголовков (header compression). При этом используются не универсальные, а специально разработанные методы. Дело в том, что по отдельности заголовки сжимаются плохо (поскольку они и так короткие), а для декомпрессии требуется, чтобы исходные данные пришли на место назначения. Последнее может и не произойти из-за потери пакетов.
Сжатие заголовков можно эффективно реализовать, если учитывать формат протокола. Одна из первых схем была разработана Ван Джейкобсоном (1990) и применялась для сжатия TCP/IP-заголовков при передаче по медленным последовательным каналам. Она позволяет уменьшить обычный 40-байтный TCP/IP-заголовок в среднем до 3 байт. Если посмотреть на илл. 6.53, можно догадаться, на чем основан этот метод. Дело в том, что многие поля заголовка не меняются от пакета к пакету. К примеру, совсем не обязательно каждый раз передавать одно и то же значение времени жизни пакета или одинаковый номер TCP-порта. Эти поля можно пропустить при передаче пакета и заполнить при получении.
Остальные поля меняются по предсказуемому сценарию. К примеру, если нет потерь, порядковые номера TCP увеличиваются по мере отправки данных. Следовательно, получатель может предсказать наиболее вероятное значение. Номер необходимо указывать, только если он отличается от ожидаемого. Но даже тогда можно передавать разность между данным номером и предыдущим (как в случае с номером подтверждения, который увеличивается, когда новые данные приходят в обратном направлении).