Ir para o conteúdo
  • Revista PROGRAMAR: Já está disponível a edição #58 da revista programar. Faz já o download aqui!

alves077

[Resolvido] [Dúvida] Passar ponteiro pelo um Pipe

Mensagens Recomendadas

alves077    0
alves077

Boa tarde,

Tenho que passar informação por named pipes, uso named pipe porque se trata de processos que não estão ligados hierarquicamente. Um dos elementos que pretendo passar é um ponteiro para um ficheiro que foi mapeado em memória. Só que não sei se têm muita lógica enviar um ponteiro de memória por um pipe named. Já que o ponteiro está relacionado com o processo pai, por isso acho que não dará bom resultado passar o ponteiro. Alguma ideia como posso fazer chegar o ponteiro pelo pipe ao outro processo? Todos minhas tentativas até agora não passaram de segment fault..

Um excerto do codigo que tenho:

Processo que escreve

typedef struct
{
   char nome[MAX];
   char *src;
   int lojas;

}bd;

bd dados;

int main()
{
   (...)

   if((fd=open(PIPE O_WRONLY)) < 0)
   {
  	 printf("Erro..");
    exit(0);
   }
   write(fd, &dados, sizeof(bd));


}

O ponteiro "char *src" nunca chega bem ao processo que escuta, dá sempre segment fault, como posso passar pelo pipe named um ponteiro?

Obrigado pela atenção,

alves077

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
Rui Carlos    312
Rui Carlos

Tens que mandar os dados, e não o apontador. O apontador não serve de nada, pois é do espaço de memória de um processo diferente.

Neste caso em particular, vais ter que enviar também o conteúdo do src, para o qual depois alocas espaço no outro processo de modo a poderes reconstruir a estrutura de dados.

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
alves077    0
alves077

Sim, percebo a ideia, mas estou com algumas dúvidas, que ainda não percebi..

Se fizer uma copia do que o apontador está apontar e enviar o conteúdo de src, e depois o outro processo voltar a alocar espaço para reconstruir a estrutura, estes dois processos vão mexer na mesma mmap?

A intenção era um mapeava o ficheiro em memória, envia informação necessária pelo pipe para que o outro processo conseguisse aceder a memoria mapeada e edita-la. E depois o processo que editou avisa de novo o outro processo, e este último grava em ficheiro esta a memória mapeada editada.

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
Rui Carlos    312
Rui Carlos

Processo trabalham em espaços de memória diferentes por omissão. Por isso, ou usas um mecanismo de memória partilhada, ou vais ter que enviar os dados de volta para o processo de origem depois de os editares.

Provavelmente o que tu queres é usar o mmap para criar um espaço de memória que um processo irá partilhar com os processos filho.

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
alves077    0
alves077

Sim eu quero user o mmap. Mas quero que processos sem ligação hierarquica consiguam aceder e esse mapeamento. O que quero é enviar alguma informação pelo Named Pipe que o processo que receba informação consiga aceder ao ficheiro mapeado em memória. Só que ainda não percebi bem que informação tenho que enviar.

Criar o mapeamento

char *src;
src = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

Estava a enviar o src pelo Named Pipe, mas é um ponteiro não têm lógica.. Só que não sei que informação tenho que enviar...

Obrigado pela atenção,

alves077

Editado por alves077

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
HappyHippyHippo    1139
HappyHippyHippo

já foi dito que mandar ponteiro não faz sentido por serem espaços de endereçamento distintos ... agora como se faz com os named pipes :

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h> 
#include <sys/shm.h>
#include <fcntl.h>
#include <unistd.h>

#define PIPE_NAME "/tmp/my.pipe"
#define MAX 256
#define BDSIZE 3

struct Item {
   char name[MAX];
   char src[MAX];
   int stores;
};

int main(int argc, char ** argv) {
   int fd = 0, i = 0;
   struct Item db[bDSIZE];

   if (argc == 1) {
       printf("command : mypipe <write|read>\n");
       exit(-1);
   }

   if (strcmp(argv[1], "write") == 0) {
       printf("Writing to named pipe ...\n");

       // create names pipe
       if (mkfifo(PIPE_NAME, 0666) != 0) {
           fprintf(stderr, "Error while opening the named pipe : %s\n", strerror(errno));
           exit(-1);
       }

       // open named pipe
       if ((fd = open(PIPE_NAME, O_WRONLY)) == 0) {
           fprintf(stderr, "Error while opening the named pipe\n");
           exit(-1);
       }

       // write something
       strcpy(db[0].name, "Name #1");
       strcpy(db[0].src, "Source #1");
       db[0].stores = 123;

       strcpy(db[1].name, "Name #2");
       strcpy(db[1].src, "Source #2");
       db[1].stores = 456;

       strcpy(db[2].name, "Name #3");
       strcpy(db[2].src, "Source #3");
       db[2].stores = 789;

       if (write(fd, &db, sizeof(db)) != sizeof(db)) {
           fprintf(stderr, "Error while writing to named pipe : %s\n", strerror(errno));
       }

       // close named pipe pipe
       close(fd);

       printf("DONE !!!\n");
   } else if (strcmp(argv[1], "read") == 0) {
       printf("Reading to named pipe ...\n");

       // open named pipe
       if ((fd = open(PIPE_NAME, O_RDONLY)) == 0) {
           fprintf(stderr, "Error while opening the named pipe\n");
           exit(-1);
       }

       // read something
       if (read(fd, &db, sizeof(db)) != sizeof(db)) {
           fprintf(stderr, "Error while reading from named pipe : %s\n", strerror(errno));
       } else {
           for (i = 0; i < BDSIZE; i++) {
               printf("DB(%d) Name   : %s\n", i, db[i].name);
               printf("DB(%d) Src    : %s\n", i, db[i].src);
               printf("DB(%d) Stores : %d\n", i, db[i].stores);
           }
       }

       // close named pipe pipe
       close(fd);
       unlink(PIPE_NAME);

       printf("DONE !!!\n");
   } else {
       printf("command : mypipe <write|read>\n");
       exit(-1);
   }

   return 0;
}

Editado por HappyHippyHippo

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
Rui Carlos    312
Rui Carlos

Nunca usei o mmap, mas pelo que percebi, tens que o chamar antes de fork, e depois de o fazeres os apontadores de cada processo irão trabalhar sobre o mesmo recurso. Penso que não precisas de pipes para nada aqui.

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
alves077    0
alves077

Sim que mandar o ponteiro não têm lógica. Minha questão agora é que informação terei que enviar para o processo que recebe a informação consiga aceder ao mmap criado pelo primeiro?

Preciso de Pipes Named, porque os processos não têm ligação hierarquica.

Editado por alves077

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
Rui Carlos    312
Rui Carlos

Se os processos não têm ligação hierárquica penso que o mmap já não vai funcionar.

Possivelmente consegues o que pretendes usando o shmget e afins. Ou então podes resolver o problema sem memória partilhada, passando a informação de um processo para o outro explicitamente com pipes, ou outro mecanismo de passagem de mensagens.

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
HappyHippyHippo    1139
HappyHippyHippo

Minha questão agora é que informação terei que enviar para o processo que recebe a informação consiga aceder ao mmap criado pelo primeiro?

isso não funciona assim

a explicação (como em quase tudo em C) está no nome da função:

m    - memory
map - map

o problema está no map. o que estás a fazer é mapear um conteúdo em memória no espaço de endereçamento local do processo

mesmo a memória partilhada não deixa de ser um mapeamento local de uma região de memória.

conclusão : nunca terás um endereço de memória real da informação, logo não existe maneira de comunicar ao segundo processo o que pretendes.

este site explica bem o que se passa : http://www.ibm.com/developerworks/aix/library/au-spunix_sharedmemory/

-------------------------------

Possivelmente consegues o que pretendes usando o shmget e afins.

nop

como disse acima, o mmap e o shmget mapeiam localmente os dados (usando coisas como o msync para manter tudo em ordem), logo, mesmo que se mapeio o ficheiro em memória partilhada, os dados só residem localmente.

exemplo:

recursos:

- dois pipes (um para enviar a key da memória partilhada e outro para notificar que pode libertar tudo)

- bloco de memória partilhada

- mapeamento do ficheiro "input.txt" na memória partilhada

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <sys/mman.h>
#include <sys/ipc.h> 
#include <sys/shm.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define PIPE_SEND_FILE "/tmp/my.send.pipe"
#define PIPE_REPLY_FILE "/tmp/my.reply.pipe"
#define SHARED_FILE "/tmp/my.shared.mem"
#define CONTENT_FILE "input.txt"

#define MAX 256
#define BDSIZE 3

void exit_error(const char * section) {
   perror(section);
   exit(-1);
}

int main(int argc, char ** argv) {
   int content_fd,
       content_size = 0,
       pipe_fd = 0,
       ok = 1,
       shmid = 0,
       i = 0;
   char * mapped = NULL,
        * check = NULL;
   struct stat sb;
   key_t shmkey;

   if (argc == 1) {
       printf("command : mypipe <write|read>\n");
       exit(-1);
   }

   if (strcmp(argv[1], "write") == 0) {
       printf("Writing to named pipe ...\n\n");

       // open content file
       if ((content_fd = open(CONTENT_FILE, O_RDWR)) == -1) {
           exit_error("open");
       }

       // retrieve the content file stats
       if (fstat(content_fd, &sb) == -1) {
           close(content_fd);
           exit_error("fstat");
       }
       content_size = sb.st_size;

       // get a shared memory key from the content file
       if ((shmkey = ftok(CONTENT_FILE, 'r')) == -1) {
           close(content_fd);
           exit_error("ftok");
       }

       // create a block of shared memory
       if ((shmid = shmget(shmkey, content_size, 0666 | IPC_CREAT)) == -1) {
           close(content_fd);
           exit_error("shmget");
       }

       // retrieve the address of the created shared memory
       if ((mapped = shmat(shmid, (void *)0, 0)) == (void *) -1) {
           close(content_fd);
           shmdt(mapped);
           exit_error("shmat");
       }

       // test data (this should be overrided by the mmap)
       sprintf(mapped, "HappyHippyHippo");

       // map the file content into the shared memory (remember this is the local mapping of the shared memory)
       if ((check = mmap(mapped, content_size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, content_fd, 0)) == MAP_FAILED) {
           close(content_fd);
           shmdt(mapped);
           exit_error("mmap");
       }

       // close content file because is already mapped into memory
       close(content_fd);

       // presenting the file content
       printf(">> file content:\n");
       for (i = 0; i < content_size; i++) {
           printf("%c", mapped[i]);
       }
       printf("\n\n");

       // sending data log
       printf(">> sending\n");
       printf("\t - shared mapped memory key  : %d\n", shmkey);
       printf("\t - shared mapped memory size : %d\n", content_size);
       printf("\n");

       // create pipe to send the data
       if (mkfifo(PIPE_SEND_FILE, 0666) != 0) {
           munmap(mapped, content_size);
           shmdt(mapped);
           exit_error("mkfifo");
       }

       // create pipe to reply to sender
       if (mkfifo(PIPE_REPLY_FILE, 0666) != 0) {
           unlink(PIPE_SEND_FILE);
           munmap(mapped, content_size);
           shmdt(mapped);
           exit_error("mkfifo");
       }

       // open send pipe
       if ((pipe_fd = open(PIPE_SEND_FILE, O_WRONLY)) == -1) {
           unlink(PIPE_SEND_FILE);
           unlink(PIPE_REPLY_FILE);
           munmap(mapped, content_size);
           shmdt(mapped);
           exit_error("open");
       }

       // write shared memory information
       if (write(pipe_fd, &shmkey, sizeof(shmkey)) != sizeof(shmkey) ||
           write(pipe_fd, &content_size, sizeof(content_size)) != sizeof(content_size)) {
           close(pipe_fd);
           unlink(PIPE_SEND_FILE);
           unlink(PIPE_REPLY_FILE);
           munmap(mapped, content_size);
           shmdt(mapped);
           exit_error("write");
       }

       // close send pipe
       close(pipe_fd);

       // open reply pipe
       if ((pipe_fd = open(PIPE_REPLY_FILE, O_RDONLY)) == -1) {
           unlink(PIPE_SEND_FILE);
           unlink(PIPE_REPLY_FILE);
           munmap(mapped, content_size);
           shmdt(mapped);
           exit_error("open");
       }

       // read notification
       if (read(pipe_fd, &ok, sizeof(ok)) != sizeof(ok)) {
           close(pipe_fd);
           unlink(PIPE_SEND_FILE);
           unlink(PIPE_REPLY_FILE);
           munmap(mapped, content_size);
           shmdt(mapped);
           exit_error("read");
       }

       // close reply pipe
       // eliminate named pipe files
       close(pipe_fd);
       unlink(PIPE_SEND_FILE);
       unlink(PIPE_REPLY_FILE);

       // presenting the file content
       printf(">> file content:\n");
       for (i = 0; i < content_size; i++) {
           printf("%c", mapped[i]);
       }
       printf("\n\n");

       // unmap the file
       // release the shared memory
       munmap(mapped, content_size);
       shmdt(mapped);

       printf("DONE !!!\n");
   } else if (strcmp(argv[1], "read") == 0) {
       printf("Reading to named pipe ...\n\n");

       // open send pipe
       if ((pipe_fd = open(PIPE_SEND_FILE, O_RDONLY)) == 0) {
           exit_error("open");
       }

       // read shared memory information
       if (read(pipe_fd, &shmkey, sizeof(shmkey)) != sizeof(shmkey) ||
           read(pipe_fd, &content_size, sizeof(content_size)) != sizeof(content_size)) {
           close(pipe_fd);
           exit_error("read");
       }

       // close send pipe
       close(pipe_fd);

       // get access to a block of shared memory
       if ((shmid = shmget(shmkey, content_size, 0666)) == -1) {
           exit_error("shmget");
       }

       // get the shared memory
       if ((mapped = shmat(shmid, (void *)0, 0)) == (void *) -1) {
           exit_error("shmat");
       }

       // received data log
       printf(">> received\n");
       printf("\t - shared mapped memory key  : %d\n", shmkey);
       printf("\t - shared mapped memory size : %d\n", content_size);
       printf("\n");

       // presenting the file content
       printf(">> file content:\n");
       for (i = 0; i < content_size; i++) {
           printf("%c", mapped[i]);
       }
       printf("\n\n");

       // open reply pipe
       if ((pipe_fd = open(PIPE_REPLY_FILE, O_WRONLY)) == 0) {
           exit_error("open");
       }

       // write ok message
       if (write(pipe_fd, &ok, sizeof(ok)) != sizeof(ok)) {
           close(pipe_fd);
           exit_error("write");
       }

       // close reply pipe
       close(pipe_fd);

       printf("DONE !!!\n");
   } else {
       printf("command : mypipe <write|read>\n");
       exit(-1);
   }

   return 0;
}

input.txt

portugal-a-programar

$ ./mypipe write
Writing to named pipe ...

>> file content:
portugal-a-programar

>> sending
 - shared mapped memory key  : 1912867548
 - shared mapped memory size : 37

>> file content:
portugal-a-programar


DONE !!!

$ ./mypipe read
Reading to named pipe ...

>> received
 - shared mapped memory key  : 1912867548
 - shared mapped memory size : 37

>> file content:
HappyHippyHippo

DONE !!!

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
alves077    0
alves077

Sim, percebo a vossa ideia. Realmente não têm muito sentido passar ponteiros pelo pipe ..

Terei que mapear a memoria no receptor.

Obrigado pela atenção,

alves077

Editado por alves077

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!

Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.

Entrar Agora


×

Aviso Sobre Cookies

Ao usar este site você aceita os nossos Termos de Uso e Política de Privacidade. Este site usa cookies para disponibilizar funcionalidades personalizadas. Para mais informações visite esta página.