Mat*_*hid 10 haskell network-programming binary-data
我正在尝试编写一个讨论二进制网络协议的小型Haskell程序,而且我遇到了一个令人惊讶的困难.
很明显二进制数据应该存储为ByteString.
问题:我应该hGet/ hPut单个多字节整数,还是更高效地构建ByteString整个事物并使用它?
看起来这个binary包应该在这里很有用.但是,binary只处理惰性 ByteString值.
问:是否hGet在偷懒 ByteString实际读取的字节严格的规定是多少?或者它是否尝试做某种懒惰的I/O?(我不想要懒惰的I/O!)
问题:为什么文档没有指定这个?
代码看起来会包含很多"获取下一个整数,将其与此值进行比较,如果没有则抛出错误,否则继续执行下一步..."我不确定如何干净地构造没有写意大利面条代码.
总之,我想要做的事情很简单,但我似乎正在努力寻找使代码看起来简单的方法.也许我只是过度思考这个并且遗漏了一些明显的东西......
回复问题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 个字节。