¿Puedo compartir un descriptor de archivo en otro proceso en Linux o son locales para el proceso?

Digamos que tengo 2 procesos, ProcessA y ProcessB. Si realizo int fd=open(somefile) en ProcessA, ¿puedo pasar el valor del descriptor de archivo fd sobre IPC a ProcessB y hacer que manipule el mismo archivo?

Puede pasar un descriptor de archivo a otro proceso sobre sockets de dominio de Unix . Aquí está el código para pasar tal descriptor de archivo, tomado de la Progtwigción de Red Unix

 ssize_t write_fd(int fd, void *ptr, size_t nbytes, int sendfd) { struct msghdr msg; struct iovec iov[1]; #ifdef HAVE_MSGHDR_MSG_CONTROL union { struct cmsghdr cm; char control[CMSG_SPACE(sizeof(int))]; } control_un; struct cmsghdr *cmptr; msg.msg_control = control_un.control; msg.msg_controllen = sizeof(control_un.control); cmptr = CMSG_FIRSTHDR(&msg); cmptr->cmsg_len = CMSG_LEN(sizeof(int)); cmptr->cmsg_level = SOL_SOCKET; cmptr->cmsg_type = SCM_RIGHTS; *((int *) CMSG_DATA(cmptr)) = sendfd; #else msg.msg_accrights = (caddr_t) &sendfd; msg.msg_accrightslen = sizeof(int); #endif msg.msg_name = NULL; msg.msg_namelen = 0; iov[0].iov_base = ptr; iov[0].iov_len = nbytes; msg.msg_iov = iov; msg.msg_iovlen = 1; return(sendmsg(fd, &msg, 0)); } /* end write_fd */ 

Y aquí está el código para recibir el descriptor de archivo

 ssize_t read_fd(int fd, void *ptr, size_t nbytes, int *recvfd) { struct msghdr msg; struct iovec iov[1]; ssize_t n; int newfd; #ifdef HAVE_MSGHDR_MSG_CONTROL union { struct cmsghdr cm; char control[CMSG_SPACE(sizeof(int))]; } control_un; struct cmsghdr *cmptr; msg.msg_control = control_un.control; msg.msg_controllen = sizeof(control_un.control); #else msg.msg_accrights = (caddr_t) &newfd; msg.msg_accrightslen = sizeof(int); #endif msg.msg_name = NULL; msg.msg_namelen = 0; iov[0].iov_base = ptr; iov[0].iov_len = nbytes; msg.msg_iov = iov; msg.msg_iovlen = 1; if ( (n = recvmsg(fd, &msg, 0)) <= 0) return(n); #ifdef HAVE_MSGHDR_MSG_CONTROL if ( (cmptr = CMSG_FIRSTHDR(&msg)) != NULL && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) { if (cmptr->cmsg_level != SOL_SOCKET) err_quit("control level != SOL_SOCKET"); if (cmptr->cmsg_type != SCM_RIGHTS) err_quit("control type != SCM_RIGHTS"); *recvfd = *((int *) CMSG_DATA(cmptr)); } else *recvfd = -1; /* descriptor was not passed */ #else /* *INDENT-OFF* */ if (msg.msg_accrightslen == sizeof(int)) *recvfd = newfd; else *recvfd = -1; /* descriptor was not passed */ /* *INDENT-ON* */ #endif return(n); } /* end read_fd */ 

Puede usar los métodos nos descritos en este hilo, o el método (más convencional), al compartirlo entre procesos relacionados (típicamente padre-hijo o hermanos) al tenerlo creado, los procesos bifurcados reciben automáticamente una copia.

De hecho, los procesos bifurcados obtienen todos sus FD y pueden usarlos a menos que los cierren (lo que generalmente es una buena idea).

Por lo tanto, si un padre bifurca a dos hijos, si ambos tienen un descriptor de archivo que no cerraron, ahora se comparte (incluso si el padre lo cierra posteriormente). Esto podría, por ejemplo, ser una tubería de un niño a otro. Así es como redireccionamientos de shell

 ls -l | more 

Trabajo.

Tenga en cuenta que en el ejemplo de arriba, la configuración de variables al recibir, como:

 msg.msg_name = NULL; msg.msg_namelen = 0; iov[0].iov_base = ptr; iov[0].iov_len = nbytes; msg.msg_iov = iov; msg.msg_iovlen = 1; 

no es requerido. La idea de una estructura de mensaje con encabezados es que el sitio receptor no tiene que saber lo que lee y puede verificar el (primer) encabezado, qué tipo de mensaje es y qué esperar.

Si ambos procesos pertenecen al mismo usuario, entonces simplemente puede hacer uso de los procfs.

 char fd_path[64]; // actual maximal length: 37 for 64bit systems snprintf(fd_path, sizeof(fd_path), "/proc/%d/fd/%d", SOURCE_PID, SOURCE_FD); int new_fd = open(fd_path, O_RDWR); 

Por supuesto, necesitaría algún mecanismo de IPC para compartir el valor de SOURCE_FD . Véase, por ejemplo, ” Linux C: al recibir una señal, ¿es posible conocer el PID del emisor? “.