Почему IO::Socket::Async не испускает завершающую букву «a»?

Мне было интересно, знает ли кто-нибудь, как обойти кодировку IO::Socket::Async, особенно недостатки, описанные это:

Например, если используется кодировка UTF-8 и последний байт в пакете декодирован как «a», он не будет передан, поскольку следующий пакет может включать в себя объединяющий символ, который вместе должен образовывать единую графему. Управляющие символы (например, \n) всегда служат границами графем, поэтому любые текстовые протоколы, использующие символы новой строки или нулевые байты в качестве разделителей, не требуют специального рассмотрения.

В настоящее время это приводит к тому, что мои сокеты пропускают последний символ в сообщениях, но я не уверен, как это обойти. Я попытался преобразовать Connection в Channel, а затем просто вставить в него глупый \n, имитируя конец ввода для сообщения, но это не сработало. Как я могу обойти эту причуду в кодировке UTF-8?

Вот MVP, чтобы воспроизвести это:

sub listen(Int $port) {
  react {
    whenever IO::Socket::Async.listen('0.0.0.0', $port) -> $connection {
      whenever $connection.Supply -> $data {
        say $data;
        $connection.print: $data;
      }
    }
  }
}

listen(9999);

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

покажите код, который вы используете ... вы пытались использовать «наречие» :bin, чтобы буфер не рассматривался как UTF-8?

zentrunix 08.01.2023 11:33

@zentrunix Я добавил простой код, который воспроизводит эту проблему.

Rawley Fowler 08.01.2023 16:41

@zentrunix Похоже, :bin сработало, тогда я просто беру Buf[uint8] и делаю .decode.Str, и это работает как шарм. Спасибо!

Rawley Fowler 08.01.2023 16:46

«Похоже, :bin сработало, тогда я просто беру Buf[uint8] и делаю .decode.Str, и это работает как шарм». Если данные не являются ASCII или подобными, это означает, что вы нарушаете кодировку Unicode, поэтому вы получите смесь правильных строк, (молча) неправильных строк и исключений декодирования.

raiph 09.01.2023 10:13
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
4
117
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Это не «недостаток»; это просто Раку, отражающий, как работает Unicode. Если вы знаете, что вам нужно обрабатывать только ASCII или Latin-1, укажите это:

whenever $connection.Supply(:enc<ascii>) -> $data { # or :enc<latin-1>
    ...
}

Если вы хотите обрабатывать текст Unicode, то необходимо иметь дело с тем фактом, что получение, например, кодовой точки для буквы «а» не дает достаточно информации для передачи полного символа, поскольку следующая кодовая точка, полученная в следующем package может быть объединяющим символом, например, акут ставится на «a». Обратите внимание, что Raku Str — это структура данных на уровне символов (в других языках строки часто представляют собой байты или кодовые точки, что создает различные проблемы, которые в значительной степени невидимы для тех, кто заботится только об английском тексте!)

Любой хорошо спроектированный сетевой протокол предоставит способ узнать, когда достигнут конец текстового содержимого. Некоторые протоколы, такие как HTTP, явно указывают длину содержимого в байтах, поэтому можно работать с уровнем байтов (:bin) и декодировать результат, увидев такое количество байтов. Другие могут использовать закрытие соединения или разрывы строк.

В заключение, семантика строк или IO::Socket::Async (и в других местах в Raku) сами по себе не являются проблемой, но они могут выявить проблемы дизайна в протоколах.

Да, я, вероятно, мог бы сформулировать это лучше. Извини за это. Ваше объяснение было превосходным, и оно помогло мне полностью понять, что происходит с UTF-8 и почему так должно быть. Спасибо!

Rawley Fowler 09.01.2023 03:39

Следует отметить, что использование «UTF-8» в этих описаниях немного вводит в заблуждение: эта проблема может возникнуть во всем, что поддерживает все многие/большинство/все кодовые точки Unicode (например, UTF-8, UTF-16, даже UCS-2) и заботится о границах графемы (об этом заботится больше вещей, чем вы думаете). Это совершенно не связано с UTF-8 как кодировкой.

Joachim Sauer 09.01.2023 13:49

@JoachimSauer Согласен. Это не связано с UTF-8, это связано практически с любой кодировкой Unicode. Я был удивлен цитатой документа в вопросе, но затем увидел, что фактическое полное предложение документа начинается «Например», которое было исключено из предоставленной цитаты. С документом все в порядке - хороший пример - но проблема, как вы подчеркиваете, является общей для Unicode. Я только что отредактировал вопрос (вставив «Например»), чтобы попытаться отвлечь читателей от мысли, что речь идет о UTF-8.

raiph 10.01.2023 00:20

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