Os soquetes de domínio FIFO, pipe e Unix são a mesma coisa no kernel do Linux?


30

Ouvi dizer que os FIFOs são nomeados pipes. E eles têm exatamente a mesma semântica. Por outro lado, acho que o soquete do domínio Unix é bastante semelhante ao pipe (embora eu nunca tenha feito uso dele). Então, eu me pergunto se todos eles se referem à mesma implementação no kernel do Linux. Qualquer ideia?


A partir da resposta abaixo, percebi que minha pergunta é ambígua e difícil de ser respondida. É provável que ninguém conheça tantos detalhes de implementação no kernel (mesmo para desenvolvedores de kernel). Se alguém puder confirmar que o soquete do domínio Unix, o pipe e o FIFO protegem todos os dados enviados na memória compartilhada no Linux, minha pergunta está resolvida. Bem ... parcialmente resolvido.
23713 Justin

FIFO = pipes nomeados! = Pipes. Os FIFOs podem ser bidirecionais como um par de soquetes. Tubos regulares são unidirecionais. Todos têm a interface e a semântica dos arquivos. Por que a implementação é importante para você?
PSKocik

Eu sei que pipes são buffers circulares e que, com o sistema STREAMS, eles podem ter implementação compartilhada, no entanto, o Linux não usa STREAMS por padrão. Acredito que o Linux codifique esses canais IPC. Eu não sinto vontade de checar, no entanto. : D Por que você não? O código está disponível ao público.
PSKocik

Se todos compartilharem a mesma implementação, sua eficiência deverá estar próxima uma da outra. E, para mim, o código do kernel é muito difícil de entender.
25415 Justin

Respostas:


35

Soquetes de domínio UNIX e FIFO podem compartilhar parte de sua implementação, mas eles são conceitualmente muito diferentes. O FIFO funciona em um nível muito baixo. Um processo grava bytes no pipe e outro lê nele. Um soquete de domínio UNIX tem o mesmo comportamento que um soquete TCP / IP.

Um soquete é bidirecional e pode ser usado por muitos processos simultaneamente. Um processo pode aceitar muitas conexões no mesmo soquete e atender a vários clientes simultaneamente. O kernel entrega um novo descritor de arquivo a cada vez connect(2)ou accept(2)é chamado no soquete. Os pacotes sempre irão para o processo correto.
Em um FIFO, isso seria impossível. Para comunicação bidirecional, você precisa de dois FIFOs e um par de FIFOs para cada um de seus clientes. Não há como escrever ou ler de maneira seletiva, porque eles são uma maneira muito mais primitiva de se comunicar.

Canos anônimos e FIFOs são muito semelhantes. A diferença é que pipes anônimos não existem como arquivos no sistema de arquivos, portanto, nenhum processo pode existir open(2). Eles são usados ​​por processos que os compartilham por outro método. Se um processo abrir um FIFOs e, em seguida, executar, por exemplo, a fork(2), seu filho herdará seus descritores de arquivo e, entre eles, o canal.

Os soquetes de domínio UNIX, pipes anônimos e FIFOs são semelhantes no fato de usarem segmentos de memória compartilhada. Os detalhes da implementação podem variar de um sistema para outro, mas a idéia é sempre a mesma: anexar a mesma porção de memória em dois processos distintos de mapeamento de memória para que eles compartilhem dados
( editar: isso seria uma maneira óbvia de implementá-lo, mas isso é não como é realmente feito no Linux, que simplesmente usa a memória do kernel para os buffers, veja a resposta em @ tjb63 abaixo).
O kernel então lida com as chamadas do sistema e abstrai o mecanismo.


"Soquetes de domínio UNIX e FIFO podem compartilhar parte de sua implementação" ... o ponto é "parte de" ... Acabei de perceber que minha pergunta é meio ambígua e é difícil de ser respondida. É provável que ninguém conheça tantos detalhes de quais partes eles compartilham no kernel (mesmo para desenvolvedores de kernel). No entanto ... alguém poderia confirmar que soquete de domínio Unix, pipe e FIFO todos eles armazenam em buffer os dados que estão sendo enviados na memória compartilhada no Linux? Se for confirmado, minha pergunta está resolvida. Bem ... parcialmente resolvido.
Justin

Bem, sim, existe um buffer gerenciado pelo kernel. Por exemplo, com FIFOs, você pode matar o escritor e o leitor ainda pode o que foi enviado para o canal antes da morte do escritor. Com soquetes, é um pouco mais complicado porque eles funcionam com um protocolo conectado. Mas se você enviar, digamos, um int para o soquete e sair do escopo para que o int seja limpo da pilha do remetente, o destinatário ainda poderá lê-lo. Portanto, há claramente um buffer em algum lugar.
Lgeorget

Relendo o comentário, não tenho certeza se estou claro aqui ... Deixe-me saber se ainda há algo incerto.
Lgeorget 15/05

Seu comentário é claro para mim.
23713 Justin

7

Há uma discussão bastante boa sobre isso aqui: http://www.slideshare.net/divyekapoor/linux-kernel-implementation-of-pipes-and-fifos

Até onde eu posso ver, tanto nos slides da apresentação quanto na fonte @ http://lxr.free-electrons.com/source/fs/pipe.c - o fifo's é implementado como um invólucro ao redor dos tubos, e os próprios tubos são implementado através do sistema de arquivos virtual pipefs.

@lgeorget - Os pipes parecem usar a memória do kernel para buffers entre os leitores e os gravadores - eles não usam 'memória compartilhada' como tal e copiam a memória entre os espaços de endereço do usuário e do kernel (por exemplo, pipe_readchamadas pipe_iov_copy_to_user, quais chamadas __copy_to_user_inatomic(ou copy_to_user) . __copy_to_user_inatomicchamadas copy_user_generic, que está no de várias implementações ASM.


4

Um "FIFO" e um " pipe nomeado " são a mesma coisa - embora seja bem diferente de como um shell lida com um "pipe" (|) entre dois comandos na linha de comando.

Um pipe nomeado (FIFO) é um único "arquivo" compartilhado por dois programas, onde um grava nele e o outro lê dele ... Um soquete, por outro lado, é uma "conexão" entre dois "arquivos" - que pode use uma rede e esteja em computadores separados - onde um programa lê / grava em um "arquivo" e outro programa lê / grava no outro ... eu não acho que eles sejam tão parecidos ... Por outro lado, ambos soquetes e pipes nomeados - assim como arquivos, dispositivos, links simbólicos - todos usam inodes e implementam alguns recursos comuns (como leitura e gravação).


1
Sim, o soquete de domínio Unix é um tipo de soquete; portanto, a API é semelhante a outras APIs de soquete, como TCP ou UDP, etc. No entanto, o soquete de domínio Unix pode ser usado apenas como IPC "local". E a maneira como ele transfere os dados é o primeiro a entrar, como o FIFO e o pipe. Então, acho que é possível que a API do soquete do domínio Unix seja apenas mais um encapsulamento de implementação idêntica, por isso a usamos como se fosse um soquete. Eu acho que é possível que todos compartilhem o mesmo interno no kernel ... Quero confirmar se é verdade ou não.
23713 Justin

1

Eu acho que não, Justin. Se não estou enganado, e possivelmente estou, acho que os FIFOs usam um arquivo em disco e os soquetes do Domínio Unix usam a memória do kernel.

Além disso, como um complemento ao pôster acima, que mencionou que os soquetes de domínio Unix são bidirecionais, esse é apenas o caso ao usar um soquete SOCK_STREAM. SOCK_DGRAM Os soquetes de domínio Unix são, de fato, unidirecionais e só podem enviar () do código que chamou connect () para o código que chamou bind ().

Obviamente, o código que chamou connect () também deve chamar bind () para criar seu próprio terminal, mas isso não tem nada a ver com sua pergunta.


3
Bem-vindo ao StackExchange, e obrigado por postar. Algumas observações ... 1) Se você está "muito possivelmente" equivocado, verifique duas vezes antes de responder; este site não é um fórum nem um bate-papo. 2) Obrigado por sua precisão nos soquetes orientados a datagramas. 3) Não há necessidade de postar algo que não tenha "nada a ver" com a pergunta. :)
lgeorget

1

Meus 2 centavos ... O soquete FIFO e UNIX são bidirecionais (semelhantes), mas o soquete tem uma topologia em estrela, enquanto um FIFO é apenas uma fila (e, portanto, não pode substituir um ao outro), sim, sua implementação pode compartilhar código internamente.

**

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 é bidirecional?
jhfrontz
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.