Почему “cat” иногда пропускает байты при чтении из другого терминала, а функция сканирования в Golang этого не делает?

Вопрос или проблема

Один вопрос, связанный с pty (псевдотерминалы) и с тем, как (cat) golang читает из них.

Сначала я сделал следующее.

  1. открыл два терминала (dev/pts/0 – 0 и dev/pts/1 – 1)
  2. затем я ввёл во втором терминале “cat dev/pts/0” (так что все, что написано в первом терминале, будет отображаться во втором)
  3. начал писать в первом терминале (TUI)

В большинстве случаев это работает, но время от времени некоторые символы пропускаются.

Точнее, для тех символов, которые не отображаются во втором терминале, у меня есть эхо, а для тех, которые отображаются, эхо нет. Это как будто эхо и cat конкурируют за символы.

Однако, когда я работаю с golang и функциями форматирования ввода, каждый раз, когда я что-то пишу в терминал (и таким образом в /dev/pts/0), функция считывания читает всё из него (нет пропущенных байт) + введённое содержимое отображается в TUI (в этом случае “эхо” работает).

package main

import "fmt"

func main() {
    var input string

    fmt.Println("Enter text:")

    for {
        fmt.Scanln(&input)
        fmt.Println("You wrote:", input)
    }
}

Таким образом, в этом случае, кажется, что “конкуренции” между эхом и golang не существует…

Я ожидаю одинакового поведения в обоих случаях. В частности, прочитать все байты в обоих случаях и иметь (или не иметь) эхо в обоих случаях.

В чем разница? Почему “cat” иногда пропускает байты при чтении из другого терминала, а функция считывания golang этого не делает? Я думал, что golang просто читает из “dev/pts/0” так же, как и “cat”, и просто выдаёт результат.

Ответ или решение

Во-первых, чтобы понять, почему "cat" иногда пропускает байты при чтении с другого терминала, а функция сканирования на Golang – нет, необходимо разобраться в базовых принципах работы с псевдотерминалами (pty).

1. Природа псевдотерминалов

Псевдотерминалы, такие как /dev/pts/0 и /dev/pts/1, создаются для симуляции работы физических терминалов. Они состоят из пары устройств: master и slave. Ваша команда cat /dev/pts/0 на втором терминале прослушивает ввод с первого терминала, создавая своеобразный канал передачи данных между ними.

2. Конкуренция между Echo и Cat

Когда вы вводите текст в первый терминал, данные поступают через tty драйвер. В зависимости от настроек терминала, tty может обрабатывать ввод различными способами, включая эхо-ввод. В случае с cat, он не контролирует эхо-ввод, поскольку эхо управляется tty драйвером. Это означает, что и cat, и эхо-ввод обращаются к одним и тем же символам, потенциально вызывая конфликты. Таким образом, некоторые символы могут быть отображены только в виде эхо-ввода или только через cat, но не через оба.

3. Обработка ввода в Golang

Воспользовавшись функцией Scanln из пакета fmt в Golang, вы получаете преимущества буферизации. Scanln ждет завершения ввода (обычно завися от нажатия Enter), прежде чем начать обработку. Таким образом, он исключает возможность конфликта с эхо-вводом, так как все данные уже находятся в формате, готовом для чтения, прежде чем Scanln их обрабатывает.

4. Различия в реализации

cat просто считывает поток данных побайтово, что делает его уязвимым к коллизиям с tty эхо-вводом. В отличие от cat, Golang с fmt.Scanln буферизует и анализирует строку целиком, после чего выводит обработанный текст, минимизируя возможность конфликтов с tty.

Заключение

Таким образом, различие в поведении cat и функции Scanln на Golang связано с тем, как они обрабатывают данные ввода. cat работает в режиме реального времени без буферизации, подвергаясь конкуренции с эхо-вводом, тогда как Golang использует буферизацию и управление вводом, чтобы избежать потери данных. Выполняя разработку приложений, взаимодействующих с терминалами, учитывайте эти аспекты для достижения требуемого поведения.

На всякий случай, при работе с cat можно рассмотреть применение переменной среды stty для настройки эхо-ввода, что может помочь снизить количество конфликтов.

Таким образом, понимание особенностей работы каждого из этих инструментов позволит вам более эффективно управлять потоками данных в сценариях с использованием псевдотерминалов.

Оцените материал
Добавить комментарий

Капча загружается...