Non è possibile trasmettere un socket (o qualsiasi altro descrittore di file) da un processo a un altro attraverso la memoria condivisa. Un descrittore di file è solo un piccolo numero intero. Inserendo questo numero intero nella memoria condivisa e accedendo da un altro processo, non automaticamente lo stesso numero intero in un descrittore di file valido dal punto di vista dell'altro processo.
Il modo corretto per inviare un descrittore di file da un processo all'altro è inviare come SCM_RIGHTS
dati ausiliari con sendmsg()
attraverso un canale di comunicazione zoccolo esistente tra i due processi.
Innanzitutto, creare il canale di comunicazione con socketpair()
prima di fork()
. Ora, nel genitore, chiudi un'estremità della coppia di socket e, nel bambino, chiudi l'altra estremità. È ora possibile sendmsg()
dal padre su un'estremità di questo socket e ricevere con recvmsg()
nel figlio utilizzando l'altra estremità.
L'invio di un messaggio con SCM_RIGHTS
sembra qualcosa di simile:
struct msghdr m;
struct cmsghdr *cm;
struct iovec iov;
char buf[CMSG_SPACE(sizeof(int))];
char dummy[2];
memset(&m, 0, sizeof(m));
m.msg_controllen = CMSG_SPACE(sizeof(int));
m.msg_control = &buf;
memset(m.msg_control, 0, m.msg_controllen);
cm = CMSG_FIRSTHDR(&m);
cm->cmsg_level = SOL_SOCKET;
cm->cmsg_type = SCM_RIGHTS;
cm->cmsg_len = CMSG_LEN(sizeof(int));
*((int *)CMSG_DATA(cm)) = your_file_descriptor_to_send;
m.msg_iov = &iov;
m.msg_iovlen = 1;
iov.iov_base = dummy;
iov.iov_len = 1;
dummy[0] = 0; /* doesn't matter what data we send */
sendmsg(fd, &m, 0);
Ricezione di un messaggio con SCM_RIGHTS
in esso più o meno così:
struct msghdr m;
struct cmsghdr *cm;
struct iovec iov;
struct dummy[100];
char buf[CMSG_SPACE(sizeof(int))];
ssize_t readlen;
int *fdlist;
iov.iov_base = dummy;
iov.iov_len = sizeof(dummy);
memset(&m, 0, sizeof(m));
m.msg_iov = &iov;
m.msg_iovlen = 1;
m.msg_controllen = CMSG_SPACE(sizeof(int));
m.msg_control = buf;
readlen = recvmsg(fd, &m, 0);
/* Do your error handling here in case recvmsg fails */
received_file_descriptor = -1; /* Default: none was received */
for (cm = CMSG_FIRSTHDR(&m); cm; cm = CMSG_NXTHDR(&m, cm)) {
if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_RIGHTS) {
nfds = (cm->cmsg_len - CMSG_LEN(0))/sizeof(int);
fdlist = (int *)CMSG_DATA(cm);
received_file_descriptor = *fdlist;
break;
}
}
stavo parlando del processo genitore/figlio, quindi la domanda è: come accedere al file del descrittore di file creato dal genitore dopo un fork? – user1995143
+1 Per una bella risposta, ma mi sembra che starebbe meglio usando i thread. –
@ user1995143 Questa è esattamente la domanda cui ho risposto. Non importa quale sia la relazione genitore/figlio dei 2 processi. Finché si dispone di un socket di dominio UNIX come canale di comunicazione, è possibile trasmettere i descrittori di file utilizzando questa tecnica. Oppure puoi seguire il suggerimento [Robert S. Barnes] (http://stackoverflow.com/users/71074/robert-s-barnes) e utilizzare più thread anziché più processi. Quindi non devi preoccuparti perché i descrittori di file sono condivisi tra tutti i thread di un singolo processo. – Celada