FIFO,管道和Unix域套接字在Linux内核中是否相同?


30

我听说FIFO被称为管道。它们具有完全相同的语义。另一方面,我认为Unix域套接字与管道非常相似(尽管我从未使用过)。因此,我想知道它们是否都引用Linux内核中的同一实现。任何的想法?


从下面的答案中,我意识到我的问题有点模棱两可,很难回答。可能没人会知道内核中这么多实现细节的细节(即使对于内核开发人员也是如此)。如果有人可以确认Unix域套接字,管道和FIFO是否都在Linux下将它们发送的数据缓冲在共享内存中,那么我的问题就解决了。好吧...部分解决了。
贾斯汀

FIFO =命名管道!=管道。FIFO可以像套接字对一样是双向的。常规管道是单向的。都具有文件接口和文件语义。为什么实施对您很重要?
PSkocik 2015年

我知道管道是循环缓冲区,并且在STREAMS系统中,它们可以共享实现,但是Linux默认情况下不使用STREAMS。我相信Linux会对这些IPC通道进行硬编码。不过,我不想检查。:D你为什么不呢?该代码是公开可用的。
PSkocik 2015年

如果它们都共享相同的实现,则它们的效率应该彼此接近。而且,对我来说,内核代码太难理解了。
贾斯汀

Answers:


35

UNIX域套接字和FIFO可以共享其实现的某些部分,但是它们在概念上是非常不同的。FIFO的功能很低。一个进程将字节写入管道,另一个进程从中读取字节。UNIX域套接字具有与TCP / IP套接字相同的行为。

套接字是双向的,可以同时被许多进程使用。一个进程可以在同一套接字上接受许多连接,并同时参与多个客户端。内核每次都会提供一个新的文件描述符,connect(2)或者accept(2)在套接字上调用它。数据包将始终进行正确的处理。
在FIFO上,这是不可能的。对于双向通信,您需要两个FIFO,并且每个客户都需要一对FIFO。没有选择性的书写或阅读方法,因为它们是一种更为原始的交流方式。

匿名管道和FIFO非常相似。区别在于,匿名管道不作为文件系统上的文件存在,因此没有进程可以处理open(2)。由其他方法共享它们的进程使用它们。如果某个进程打开一个FIFO,然后执行例如a fork(2),则其子进程将继承其文件描述符,并在其中包括管道。

UNIX域套接字,匿名管道和FIFO在使用共享内存段方面是相似的。实现的细节可能因一个系统而异,但是思想始终是相同的:在两个不同的进程中将相同的内存部分附加到内存映射中,以使它们共享数据
编辑:这是一种实现它的明显方式,但是而不是在Linux中的实际操作,Linux仅使用内核内存作为缓冲区,请参见下面的@ tjb63回答)。
然后内核处理系统调用并抽象化该机制。


“ UNIX域套接字和FIFO可能共享其实现的某些部分”……重点是“其中的一部分”……我刚刚意识到我的问题有点模棱两可,很难回答。可能没有人知道他们在内核中共享哪些部分的太多细节(即使对于内核开发人员也是如此)。但是...有人能确认Unix域套接字,管道和FIFO是否都将正在Linux下共享存储器中发送的数据缓冲吗?如果确认,我的问题就解决了。好吧...部分解决了。
贾斯汀

好吧,是的,有一个由内核管理的缓冲区。例如,使用FIFO,您可以杀死写入者,而读取者仍然可以在写入者去世之前将发送到管道中的内容杀死。对于套接字,它有点复杂,因为它们可以通过连接的协议来工作。但是,如果您将一个int发送给套接字,然后超出范围,以便从发送方堆栈中清除该int,则接收方仍然可以读取它。因此,显然在某处有缓冲区。
lgeorget

重新阅读评论,不确定在这里是否清楚...让我知道是否还有不清楚的地方。
lgeorget

您的评论对我很清楚。
贾斯汀

7

这里对此进行了很好的讨论:http : //www.slideshare.net/divyekapoor/linux-kernel-implementation-of-pipes-and-fifos

据我所知,无论是从演示幻灯片,还是从@ http://lxr.free-electrons.com/source/fs/pipe.c的源代码中,-fifo都是作为管道的包装而实现的,而管道本身就是通过pipefs虚拟文件系统实现。

@lgeorget-管道似乎在读取器和写入器之间使用内核内存作为缓冲区–它们不使用“共享内存”,而是在用户和内核地址空间之间复制内存(例如,pipe_read调用pipe_iov_copy_to_user,调用__copy_to_user_inatomic(或copy_to_user)) 。__copy_to_user_inatomic通话copy_user_generic,这是几个ASM实现的。


4

“ FIFO”和“ 命名管道”是同一件事-尽管它与shell在命令行上的两个命令之间处理“管道”(|)的方式完全不同。

命名管道(FIFO)是由两个程序共享的单个“文件”,其中一个程序对其进行写入,另一个程序则从该文件中读取...另一方面,套接字是两个“文件”之间的“连接”,这可能使用网络并位于单独的计算机上-其中一个程序读取/写入一个“文件”,另一个程序读取/写入另一个“文件” ...我不认为它们是如此相似...另一方面套接字和命名管道-以及文件,设备,符号链接-均使用inode,并且它们都实现了一些通用功能(例如读取和写入)。


1
是的,Unix域套接字是一种套接字,因此它的API与其他套接字API(例如TCP或UDP等)相似。但是,Unix域套接字只能用作“本地” IPC。数据传输的方式是先进先出,非常类似于FIFO和管道。因此,我认为Unix域套接字的API可能只是相同实现的另一种封装,因此我们将其当作套接字使用。我认为它们有可能在内核中共享相同的内部 ...我想确认一下这是否正确。
贾斯汀

1

我不认为贾斯汀。如果我没记错的话,很可能是这样,我认为FIFO使用磁盘上的文件,而Unix Domain套接字使用内核内存。

另外,除了上面提到的Unix域套接字是双向的,还包括使用SOCK_STREAM套接字的情况。SOCK_DGRAM实际上,Unix域套接字是单向的,并且只能从调用connect()的代码发送到调用bind()的代码。

当然,调用connect()的代码也必须调用bind()来创建自己的端点,但这与您的问题无关。


3
欢迎使用StackExchange,并感谢您的发布。几点评论... 1)如果您“很可能”错误,则应在回答前仔细检查;该网站既不是论坛也不是聊天。2)感谢您在面向数据报的套接字上的精确度。3)无需发布与该问题“无关”的内容。:)
lgeorget13年

1

我的2 cents ... FIFO和UNIX套接字都是双向的(相似的),但是套接字具有星形拓扑,而FIFO只是一个队列(因此​​不能互相替换),是的,它们的实现可以在内部共享代码。

**

char * myfifo = "/tmp/myfifo";
mkfifo(myfifo, 0666);
fd = open(myfifo, O_RDWR);   //so that you can read/write to it
 ...
write(fd, buff1, sizeof(buff1));  
getchar();//wait till some one reds this and writes something else
int sz=read(fd, buff1, sizeof(buff1));  //read that something**

FIFO是双向的吗?
jhfrontz
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.