2017-04-03 73 views
-1

我在这里发现了很多线程,询问如何在写入之后刷管道而不关闭它。 在每一个线程中,我可以看到不同的建议,但我找不到明确的解决方案。冲洗管道不关闭C

这里是一个快速摘要:

  1. 最简单的方式,以避免读取管道阻塞是写即读字节的确切数量。

  2. 它也可以通过使用ptmx而不是管道来完成,但人们说这可能会很多。

注:这是不可能使用的fsync与管道

是否有其他更有效的解决方案?

编辑:当发送者想要写的n个字符,但客户端读取米字符(其中,M> N)

冲洗将是方便的。客户端将阻止等待另一个m-n个字符。如果发件人希望再次与客户端通信,则无需关闭管道,只需发送确切数量的字节就可以成为错误的良好来源。

接收器操作这样的,它不能被修改:

while((n=read(0, buf, 100)>0){ 
    process(buf) 

使发送者希望得到处理:“文件1”和“文件2”为将要:

write(pipe[1], "file1\0*95", 100); 
write(pipe[1], "file2\0*95", 100); 

我正在寻找一种方式来做类似的事情(不必使用\ n作为分隔符):

write(pipe[1], "file1\nfile2", 11); //it would have worked if it was ptmx 

(使用读取和写入)

+2

这听起来很像[X-Y问题](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)。一般来说,不需要冲洗管道,那么真正的问题是什么? –

+0

你是什么意思的“点”? –

+0

@John:我指的是伪终端主/从。我已更新原始帖子。 –

回答

1

冲洗的fflush()意义上与管道无关,因为它们不表示为C流。因此没有用户级缓冲区来刷新。同样,fsync()也与管道无关,因为数据没有后端存储。成功写入管道的数据存在于内核中,并且只有在内核中才会成功读取,因此fsync()无法工作。总体而言,冲洗/同步仅适用于涉及中间存储的情况,管道不属于这种情况。

澄清之后,您的问题似乎是建立通过管道进行通信的消息边界。你是正确的,关闭管道的写入结束将发出一个边界 - 不仅仅是一条消息,而是整个通信流 - 但当然这是最终的。你也没有固有的信息边界是正确的。不过,你似乎是从这里一个误解,至少有些工作:

最简单的方式,以避免读取上阻塞管道是写 所读取字节的确切数量。

[...]

当发送者想写入 个字符但客户端读取m个字符(其中m> n)时,刷新会很方便。客户端 将阻止等待另一个m-n个字符。

读者是否会阻止完全取决于读者如何实施。特别是,系统调用不保证在返回之前传送所请求的字节数。在某些情况下,它可以并将执行简短的阅读。虽然细节没有详细说明,但至少可以传输一个字符而不会阻塞,但不能传输请求的整个数字,您通常可以依靠简短的阅读。类似的情况也适用于write(2)。因此,避免read()阻塞的最简单方法是确保您至少写入一个字节到用于该read()调用的管道传输。

事实上,人们通常从相反的方向来看这个问题:需要确定接收特定数量的字节,因此不得不将短读取作为并发症进行处理(将由循环执行read())。您也需要考虑这一点,但您的客户在您描述的情况下不太可能阻止您的好处;它只是不是你认为的问题。

然而,在任何类型的流通信中都存在固有的消息边界问题,您需要处理它。有几种方法;其中最常用的是

  • 固定长度消息。接收器可以读取,直到它成功传输所需的字节数;涉及的任何阻塞都是适当且需要的。采用这种方法,你所假设的场景根本不会出现,但作者可能需要填充其消息。

  • 分隔邮件。接收器然后读取,直到它发现它已收到一个消息分隔符(例如换行符或空字节)。在这种情况下,接收方需要准备好消息边界不会与read()调用传输的字节序列对齐的可能性。通过关闭通道标记消息的结尾可以被认为是这种替代方案的特例。

  • 嵌入的消息长度元数据。这可以采取多种形式,但最简单的一种方法是将消息构造为固定长度的整数消息长度字段,然后是消息数据的该字节数。读者在每一点都知道它需要读取多少字节,所以它不会不必要地阻塞。

这些可以单独使用或组合使用来实现应用层协议,以便在进程之间进行通信。自然,通信双方必须就通信协议的细节达成一致才能成功。

+0

感谢您的回复。我在原来的问题中增加了一些注释,但是我所看到的是这样的答案:“它可以并且将在某些情况下执行一个简短的阅读”这些情况是哪些? –

+0

@AntonisParagas,我已经在最大程度上回答了我的答案:“尽管**的细节没有说明,但通常您可以依靠简短的阅读,至少有一个角色可以传输而不会阻塞,但不能要求的整个号码。“也就是说,read()通常不会传输至少一个字节。 –