Как вы читаете, не указывая длину фрагмента байта заранее, с помощью net.TCPConn в golang?

#tcp #go

#tcp #Вперед

Вопрос:

Я пытался прочитать некоторые сообщения из tcp-соединения с клиентом redis (терминал, на котором только что запущен redis-cli). Однако команда Read для пакета net требует, чтобы я ввел фрагмент в качестве аргумента. Всякий раз, когда я предоставляю фрагмент без длины, происходит сбой соединения и программа go останавливается. Я не уверен, какой длины должны быть мои байтовые сообщения перед отправкой. Итак, если я не укажу какой-либо фрагмент, который смехотворно велик, это соединение всегда будет закрываться, хотя это кажется расточительным. Мне было интересно, возможно ли поддерживать соединение, не зная заранее длину сообщения? Я хотел бы получить решение моей конкретной проблемы, но я чувствую, что этот вопрос более общий. Почему мне нужно знать длину заранее? Не может ли библиотека просто предоставить мне фрагмент правильного размера?

Или какое другое решение предлагают люди?

Комментарии:

1. Можете ли вы опубликовать сообщение об ошибке?

2. Да, за ошибкой EOF следует exit status 1 .

3. Я не возражаю против удара слева, но предварительный фрагмент следует использовать только при защите на полном ходу или иногда при переходе в сеть.

Ответ №1:

Именно по этой причине вы должны указать размер для чтения, не зная размера сообщения (это относится к любой сетевой библиотеке, а не только к Go). TCP — это потоковый протокол. Что касается протокола TCP, сообщение продолжается до тех пор, пока соединение не будет закрыто.

Если вы знаете, что собираетесь читать до EOF, используйте ioutil.ReadAll

Вызов Read не гарантирует, что вы получите все, что вы ожидаете. Он может возвращать меньше, он может возвращать больше, в зависимости от того, сколько данных вы получили. Библиотеки, которые выполняют ввод-вывод, обычно читают и записывают через «буфер»; у вас будет свой «буфер чтения», который представляет собой предварительно выделенный фрагмент байтов (обычно до 32 кб), и вы повторно используете этот фрагмент каждый раз, когда хотите прочитать из сети. Вот почему функции ввода-вывода возвращают количество байтов, чтобы вы знали, какая часть буфера была заполнена последней операцией. Если буфер был заполнен или вы все еще ожидаете больше данных, вы просто вызываете Read еще раз.

Комментарии:

1. О, спасибо! Я просто не понимаю, почему кто-то не дочитал до конца сообщение? является ли EOF тем же самым до конца сообщения? Почему эта деталь просто не скрыта / абстрагирована от программиста? Почему это есть в любой сетевой библиотеке?

2. EOF — это не конец сообщения, это закрываемое соединение. TCP используется не только для отправки отдельных фрагментов данных, это поток, который вы можете использовать для отправки и получения сообщений. Сетевое соединение даже не знает, что такое «сообщение», это зависит от приложения, чтобы определить, как данные оформляются.

3. @Pinocchio, вот почему использование Type-Length-Value scheme довольно часто используется для реализации протоколов прикладного уровня, которые используют потоковые протоколы, такие как TCP.

Ответ №2:

Немного поздно, но…

  1. Один из вопросов заключался в том, как определить размер сообщения. Ответ, данный JimB, заключался в том, что TCP — это потоковый протокол, поэтому реального конца нет.
  2. Я считаю, что этот ответ неверен. TCP разделяет поток битов на последовательные пакеты. У каждого пакета есть заголовок IP и заголовок TCP, смотрите Википедию и здесь. IP-заголовок каждого пакета содержит поле для длины этого пакета. Вам пришлось бы выполнить некоторую математику, чтобы вычесть длину заголовка TCP, чтобы получить фактическую длину данных. Кроме того, максимальная длина сообщения может быть указана в заголовке TCP.
  3. Таким образом, вы можете предоставить буфер достаточной длины для вашей операции чтения. Однако сначала вы должны прочитать информацию заголовка пакета. Вероятно, вам не следует принимать TCP-соединение, если максимальный размер сообщения больше, чем вы готовы принять.
  4. Обычно отправитель прерывает соединение пакетом fin (см. 1), а не символом EOF.
  5. EOF в операции чтения, скорее всего, будет указывать на то, что пакет не был полностью передан в течение отведенного времени.