Exemplo 1: Envio de uma mensagem ao usuário
Este programa permite que processos troquem mensagens com ajuda do sistema de correio eletrônico.
/* arquivo test_pipe_mail.c */
/* teste do envio de um mail usando tubos */
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
int main()
{
FILE *fp;
int pid, pipefds[2];
char *username, *getlogin();
/* da o nome do usuario */
if ((username = getlogin()) == NULL) {
fprintf(stderr, "quem e voce?\n");
exit(1); }
/* Cria um tubo. Isto deve ser feito antes do fork para que
* o filho possa herdar esse tubo
*/
if (pipe(pipefds) < 0) { perror("Error pipe");
exit(1); }
if ((pid = fork()) < 0) { perror("Error fork");
exit(1); }
/* Codigo do filho:
* executa o comando mail e entao envia ao username
* a mensagem contida no tubo */
if (pid == 0) {
/* redirige a stdout para o tubo; o comando executado em seguida tera
como entrada (uma mensagem) a leitura do tubo */
close(0);
dup(pipefds[0]);
close(pipefds[0]);
/* fecha o lado de escrita do tubo, para poder ver a saida na tela */
close(pipefds[1]);
/* executa o comando mail */
execl("/bin/mail", "mail", username, 0);
perror("Error execl");
exit(1);
}
/* Codigo do pai:
* escreve uma mensagem no tubo */
close(pipefds[0]);
fp = fdopen(pipefds[1], "w");
fprintf(fp, "Hello from your program.\n");
fclose(fp);
/* Espera da morte do processo filho */
while (wait((int *) 0) != pid) ;
exit(0);
}
Resultado da execução: O usuário que executa o programa vai enviar a si mesmo um mensagem por correio eletrônico. A mensagem deve ser exatamente igual à mostrada a seguir:
Date: Fri, 13 Oct 2000 10:28:34 -0200 From: Celso Alberto Saibel Santos <saibel@leca.ufrn.br> To: saibel@leca.ufrn.br Hello from your program.
Exemplo 2: Enfoca mais uma vez a herança dos descritores através de um fork(). O programa cria um tubo para a comunicação entre um processo pai e seu filho.
/* arquivo test_pipe_fork.c */
/* Testa heranca dos descritores na chamada do fork().
* O programa cria um tubo e depois faz um fork. O filho
* vai se comunicar com o pai atraves desse tubo
*/
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#define DATA "Testando envio de mensagem usando pipes"
int main()
{
int sockets[2], child;
char buf[1024];
/* criacao de um tubo */
if ( pipe(sockets) == -1 ) {
perror("Error opening stream socket pair") ;
exit(10);
}
/* criacao de um filho */
if ( (child = fork()) == -1)
perror ("Error fork") ;
else if (child) {
/* Esta ainda e a execução do pai. Ele lê a mensagem do filho */
if ( close(sockets[1]) == -1) /* fecha o descritor nao utilizado */
perror("Error close") ;
if (read(sockets[0], buf, 1024) < 0 )
perror("Error: reading message");
printf("-->%s\n", buf);
close(sockets[0]);
} else {
/* Esse e o filho. Ele escreve a mensagem para seu pai */
if ( close(sockets[0]) == -1) /* fecha o descritor nao utilizado */
perror("Error close") ;
if (write(sockets[1], DATA, sizeof(DATA)) < 0 )
perror("Error: writing message");
close(sockets[1]);
}
sleep(1);
exit(0);
}
Resultado da execução:
euler:~/> test_pipe_fork -->Testando envio de mensagem usando pipes euler:~/>
Um tubo é criado pelo processo pai, o qual logo após faz um fork. Quando um processo faz um fork, a tabela de descritores do pai é automaticamente copiada para o processo filho.
No programa, o pai faz um chamada de sistema pipe() para criar um tubo. Esta rotina cria um tubo e inclui na tabela de descritores do processos os descritores para os sockets associados às duas extremidades do tubo. Note que as extremidades do tubo não são equivalentes: o sockets com índice 0 está sendo aberto para leitura, enquanto que o de índice 1 está sendo aberto somente para a escrita. Isto corresponde ao fato de que a entrada padrão na tabela de descritores é associada ao primeiro descritor, enquanto a saída padrão é associada ao segundo.
Após ser criado, o tubo será compartilhado entre pai e filho após a chamada fork. A figura 4.5.1 ilustra o efeito da chamada fork.
A tabela de descritores do processo pai aponta para ambas as extremidades do tubo. Após o fork, ambas as tabelas do pai e do filho estarão apontando para o mesmo tubo (herança de descritores). O filho então usa o tubo para enviar a mensagem para o pai.