2010-03-01 47 views
44

假設我有2個進程ProcessA和ProcessB。如果我在ProcessA中執行int fd=open(somefile),那麼我可以通過IPC將文件描述符fd的值傳遞給ProcessB,並讓它處理相同的文件?我可以在Linux上共享一個文件描述符到另一個進程嗎?還是他們在進程本地?

+1

Duplicate:http://stackoverflow.com/questions/1997622 – Zitrax 2010-03-01 22:21:17

+1

請參閱[這個問題](http://stackoverflow.com/questions/1997622)。 – bmargulies 2010-03-01 20:10:21

回答

46

您可以通過unix domain套接字將文件描述符傳遞給另一個進程。 這裏是通過這樣一個文件描述符的代碼,從Unix Network Programming

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 */ 

採取下面是接收文件描述符

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 */ 
代碼
+13

請注意,雖然文件描述符的實際數值在兩個進程中通常會有所不同。 – caf 2010-03-01 21:31:11

+1

您可以通過*號碼*這種方式。這並不神奇地表示它將作爲兩端文件描述符對同一個文件起作用。 – EJP 2014-05-12 08:50:40

+4

@EJP與SCM_RIGHTS的想法是,它會。雖然沒有人想到,但我確信有一些警告。 (即,這個概念非常像dup(),但是在不相關的進程之間) – nos 2014-05-12 10:12:53

2

您可以使用此線程所描述的方法號,或(更常規)的方式,通過在相關進程(通常是父 - 子或同級)之間共享它,分叉進程會自動接收一個副本。

實際上,分叉進程可以獲得所有的FD並可以使用它們,除非它們關閉它們(這通常是個好主意)。

因此,如果父母派生兩個孩子,如果他們都有一個文件描述符他們沒有關閉,它現在被共享(即使父母隨後關閉它)。例如,這可能是從一個孩子到另一個孩子的管道。這就是外殼重定向的方式

ls -l | more 

工作。

2

注意,在上面的例子中,變量的設置接收時,如:

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; 

不是必需的。帶有標題的消息結構的全部概念是,接收站點不必知道它讀取的內容,並且可以通過檢查(第一個)標題,它是什麼類型的消息以及期望的內容。

+0

雖然技術上是正確的,但在這種情況下指定緩衝區有一個很好的理由:爲了發送OOB消息(套接字控制消息在這種情況下),您需要指定一個非空消息(請參閱unix_stream_sendmsg,例如http://lxr.free-electrons.com/source/net/unix/af_unix.c#L1836)。當沒有iovec的時候,Linux會一遍又一遍地傳遞這個消息。因此,要讀取多個OOB消息,您必須在某個時刻讀取消息數據。 – Michael 2017-01-05 18:26:59

1

如果兩個進程屬於同一個用戶,那麼您可以簡單地使用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); 

當然,您需要一些IPC機制來共享SOURCE_FD的值。見例如「Linux C: upon receiving a signal, is it possible to know the PID of the sender?」。

+0

你是說snprintf中的「/ proc /%d/fd /%d」嗎? – kaiwan 2017-07-10 07:01:53

+0

@ kaiwan,是的。修正了,謝謝! – kay 2017-07-10 09:38:57

相關問題