Как я могу читать данные из сокета, пока ничего не осталось? - PullRequest
2 голосов
/ 16 марта 2020

Функция recv в Network.Socket или Network.Socket.Bytestring требует аргументов - длины данных для чтения. В моем проекте я не могу знать длину данных для чтения из сокета.

И я хочу: а) прочитать все данные, которые собираются вместе, б) и объединить их

Например, в Эликсире это делает то, что я хочу:

:gen_tcp.recv(my_socket, 0)

В Haskell Я думаю, что могу сделать это в al oop, с fix. Но как аккуратно сделать это с recv, собрать и вернуть целое ByteString из всех oop?

Кроме того, в документации говорится, что если recv возвращает 0 байтов, это означает, что сокет другой стороны был закрыт. Однако это не означает, что все данные были прочитаны, и поэтому они были закрыты, не так ли? Если правильно, как я могу это обнаружить?

Ответы [ 2 ]

2 голосов
/ 16 марта 2020

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

0 голосов
/ 17 марта 2020

Самым простым и лучшим решением может быть преобразование сокета в Handle и чтение его как таковое, как предлагается в другом ответе, но вот один из способов сделать это, используя recv:

import Network.Socket
import Network.Socket.ByteString
import qualified Data.ByteString as B
import qualified Data.ByteString.Builder as BB
import qualified Data.ByteString.Lazy as BL
import Data.Monoid (mempty,(<>))

readAll :: Socket -> IO BL.ByteString
readAll sock = go (mempty :: BB.Builder)
  where
    go b = do
        bytes <- recv sock 1024 
        if B.length bytes == 0
           then pure $ BB.toLazyByteString b
           else go (b <> BB.byteString bytes)

Существует 3 основных типа:

  • B.ByteString В основном массив байтов в памяти.
  • BB.Builder Может быть создан из B.ByteString и поддерживает эффективную конкатенацию с Monoid методом mappend (что совпадает с <> оператор). Может быть преобразовано в BL.ByteString.
  • BL.ByteString Внутренне, список значений B.ByteString. Внешне интерфейс очень похож на B.ByteString. Может быть «спрессован» в один непрерывный B.ByteString с использованием BL.toStrict.

В качестве альтернативы модуль Network.Socket.ByteString.Lazy обеспечивает getContents, но эта функция использует ленивый ввод / вывод, который труден для понимания и может вызывать неприятные сюрпризы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...