通过网络实现高效的二进制I/O.

Mat*_*hid 10 haskell network-programming binary-data

我正在尝试编写一个讨论二进制网络协议的小型Haskell程序,而且我遇到了一个令人惊讶的困难.

很明显二进制数据应该存储为ByteString.

问题:我应该hGet/ hPut单个多字节整数,还是更高效地构建ByteString整个事物并使用它?

看起来这个binary包应该在这里很有用.但是,binary只处理惰性 ByteString值.

问:是否hGet偷懒 ByteString实际读取的字节严格的规定是多少?或者它是否尝试做某种懒惰的I/O?(我想要懒惰的I/O!)

问题:为什么文档没有指定这个?

代码看起来会包含很多"获取下一个整数,将其与此值进行比较,如果没有则抛出错误,否则继续执行下一步..."我不确定如何干净地构造没有写意大利面条代码.

总之,我想要做的事情很简单,但我似乎正在努力寻找使代码看起来简单的方法.也许我只是过度思考这个并且遗漏了一些明显的东西......

Eri*_*ikR 2

回复问题1...

如果配置了句柄,则NoBuffering每次hPutStr调用都会生成一个 write 系统调用。对于大量的小写操作,这将带来巨大的性能损失。例如,请参阅此 SO 答案以进行一些基准测试:/sf/answers/1970267421/

另一方面,如果句柄启用了缓冲,则需要显式刷新句柄以确保发送缓冲数据。

我假设您使用的是 TCP 之类的流协议。对于 UDP,您显然必须将每条消息作为一个原子单元来形成和发送。

回复问题 #2...

阅读代码后发现,hGet对于惰性字节串,将从句柄中读取defaultChunkSize大约 32k 的块。

更新:在这种情况下,hGet 似乎不执行惰性 IO。这是一些测试代码。喂养:

#!/usr/bin/env perl
$| = 1;
my $c = 0;
my $k = "1" x 1024;
while (1) {
  syswrite(STDOUT, $k);
  $c++;
  print STDERR "wrote 1k count = $c\n";
}
Run Code Online (Sandbox Code Playgroud)

测试.hs:

import qualified Data.ByteString.Lazy as LBS
import System.IO

main = do
  s <- LBS.hGet stdin 320000
  let s2 = LBS.take 10 s
  print $ ("Length s2 = ", s2)
Run Code Online (Sandbox Code Playgroud)

运行perl feed | runhaskell Test.hs 很明显,Haskell 程序要求 perl 程序提供全部 320k,即使它只使用前 10 个字节。