简体   繁体   English

不关闭C冲洗管道

[英]Flushing pipe without closing in C

I have found a lot of threads in here asking about how it is possible to flush a pipe after writing to it without closing it. 我在这里发现了很多线程,询问如何在写入管道后不关闭管道的情况下刷新管道。 In every thread I could see different suggestions but i could not find a definite solution. 在每个线程中,我可以看到不同的建议,但找不到明确的解决方案。

Here is a quick summary: 快速摘要:

  1. The easiest way to avoid read blocking on the pipe would be to write the exact number of bytes that is reading. 避免管道上的读取阻塞的最简单方法是写入正在读取的确切字节数。

  2. It could be also done by using ptmx instead of a pipe but people said it could be to much. 也可以通过使用ptmx而不是管道来完成此操作,但人们表示这可能会很多。

Note: It's not possible to use fsync with pipes 注意:不能对管道使用fsync

Are there any other more efficient solutions? 还有其他更有效的解决方案吗?

Edit: 编辑:

The flush would be convenient when the sender wants to write n characters but the client reads m characters (where m>n). 当发送方要写入n个字符但客户端读取m个字符(其中m> n)时,刷新将很方便。 The client will block waiting for another mn characters. 客户端将阻止等待另外mn个字符。 If the sender wants to communicate again with the client leaves him without the option of closing the pipe and just sending the exact number of bytes could be a good source of bugs. 如果发件人想与客户端再次进行通信,而没有关闭管道的选择,而仅发送确切数量的字节,则可能是错误的一个好来源。

The receiver operates like this and it cannot be modified: 接收器的运行方式如下,无法修改:

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

so the sender wants to get processed: "file1" and "file2" for which will have to: 因此,发件人希望得到处理:“ file1”和“ file2”必须为此:

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

what I am looking is for a way to do something like that (without being necessary to use the \\n as the delimeter): 我正在寻找的是一种可以执行类似操作的方法(无需使用\\ n作为分隔符):

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

(Using read and write) (使用读写)

Flushing in the sense of fflush() is irrelevant to pipes, because they are not represented as C streams. fflush()的意义上的冲洗与管道无关,因为它们未表示为C流。 There is therefore no userland buffer to flush. 因此,没有要刷新的用户区缓冲区。 Similarly, fsync() is also irrelevant to pipes, because there is no back-end storage for the data. 同样, fsync()也与管道无关,因为没有用于数据的后端存储。 Data successfully written to a pipe exist in the kernel and only in the kernel until they are successfully read, so there is no work for fsync() to do. 成功写入管道的数据存在于内核中,并且仅在内核中存在,直到成功读取它们为止,因此fsync()不需要做任何工作。 Overall, flushing / syncing is applicable only where there is intermediate storage involved, which is not the case with pipes. 总体而言,刷新/同步仅适用于涉及中间存储的地方,而管道不适用。

With the clarification, your question seems to be about establishing message boundaries for communication via a pipe. 澄清之后,您的问题似乎与建立通过管道进行通信的消息边界有关。 You are correct that closing the write end of the pipe will signal a boundary -- not just of one message, but of the whole stream of communication -- but of course that's final. 您是正确的,关闭管道的写端将发出信号边界-不仅是一条消息,而且是整个通信流的边界-当然,这是最终的。 You are also correct that there are no inherent message boundaries. 您也没有任何固有的消息边界是正确的。 Nevertheless, you seem to be working from at least somewhat of a misconception here: 但是,您似乎至少在某种程度上误解了:

The easiest way to avoid read blocking on the pipe would be to write the exact number of bytes that is reading. 避免管道上的读取阻塞的最简单方法是写入正在读取的确切字节数。

[...] [...]

The flush would be convenient when the sender wants to write n characters but the client reads m characters (where m>n). 当发送方要写入n个字符但客户端读取m个字符(其中m> n)时,刷新将很方便。 The client will block waiting for another mn characters. 客户端将阻止等待另外mn个字符。

Whether the reader will block is entirely dependent on how the reader is implemented. 阅读器是否会阻塞完全取决于阅读器的实现方式。 In particular, the read(2) system call in no way guarantees to transfer the requested number of bytes before returning. 特别是, read(2)系统调用绝不能保证在返回之前传输请求的字节数。 It can and will perform a short read under some circumstances. 在某些情况下,它可以并且将进行简短的阅读。 Although the details are unspecified, you can ordinarily rely on a short read when at least one character can be transferred without blocking, but not the whole number requested. 尽管未指定详细信息,但通常可以依靠短读来传输至少一个字符而不会阻塞而不是请求的整数。 Similar applies to write(2) . 类似的适用于write(2) Thus, the easiest way to avoid read() blocking is to ensure that you write at least one byte to the pipe for that read() call to transfer. 因此,避免read()阻塞的最简单方法是确保为该read()调用转移至少一个字节到管道。

In fact, people usually come at this issue from the opposite direction: needing to be certain to receive a specific number of bytes, and therefore having to deal with the potential for short reads as a complication (to be dealt with by performing the read() in a loop). 实际上,人们通常会从相反的方向遇到这个问题:需要确定接收特定数量的字节,因此必须将短读取的潜在可能性作为一个复杂问题来处理(通过执行read()在一个循环中)。 You'll need to consider that, too, but you have the benefit that your client is unlikely to block under the circumstances you describe; 您也需要考虑到这一点,但是这样做的好处是,您的客户在您描述的情况下不太可能被阻止; it just isn't the problem you think it is. 这不是您认为的问题。

There is an inherent message-boundary problem in any kind of stream communication, however, and you'll need to deal with it. 但是,任何一种流通信中都存在一个固有的消息边界问题,您需要对其进行处理。 There are several approaches; 有几种方法。 among the most commonly used are 其中最常用的是

  • Fixed-length messages. 定长消息。 The receiver can then read until it successfully transfers the required number of bytes; 然后,接收器可以读取直到成功传输所需的字节数为止。 any blocking involved is appropriate and needful. 任何涉及的阻止都是适当且必要的。 With this approach, the scenario you postulate simply does not arise, but the writer might need to pad its messages. 使用这种方法,根本不会出现您假设的情况,但是编写者可能需要填充其消息。

  • Delimited messages. 分隔的消息。 The receiver then reads until it finds that it has received a message delimiter (a newline or a null byte, for example). 然后,接收器进行读取,直到发现接收到消息定界符(例如,换行符或空字节)为止。 In this case, the receiver will need to be prepared for the possibility of message boundaries not being aligned with the byte sequences transferred by read() calls. 在这种情况下,将需要为接收器做好准备,以防止消息边界与read()调用传输的字节序列不对齐。 Marking the end of a message by closing the channel can be considered a special case of this alternative. 通过关闭通道来标记消息的结尾可以认为是该替代方法的一种特殊情况。

  • Embedded message-length metadata. 嵌入式消息长度元数据。 This can take many forms, but one of the simplest is to structure messages as a fixed-length integer message length field, followed by that number of bytes of message data. 这可以采用多种形式,但是最简单的方法之一是将消息构造为固定长度的整数消息长度字段,然后是该消息数据的字节数。 The reader then knows at every point how many bytes it needs to read, so it will not block needlessly. 然后,阅读器会在每个点知道需要读取多少字节,因此不会不必要地进行阻塞。

These can be used individually or in combination to implement an application-layer protocol for communicating between your processes. 这些可以单独使用,也可以组合使用以实现用于在进程之间进行通信的应用程序层协议。 Naturally, the parties to the communication must agree on the protocol details for communication to be successful. 自然,通信各方必须就协议细节达成一致,以使通信成功。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM