Создание дескриптора файла процесса, доступного для любого процесса [duplicate]

Также стоит отметить, что вы можете использовать * и ** при вызове функций. Это ярлык, который позволяет передавать несколько аргументов функции напрямую, используя либо список / кортеж, либо словарь. Например, если у вас есть следующая функция:

def foo(x,y,z):
    print("x=" + str(x))
    print("y=" + str(y))
    print("z=" + str(z))

Вы можете делать такие вещи, как:

>>> mylist = [1,2,3]
>>> foo(*mylist)
x=1
y=2
z=3

>>> mydict = {'x':1,'y':2,'z':3}
>>> foo(**mydict)
x=1
y=2
z=3

>>> mytuple = (1, 2, 3)
>>> foo(*mytuple)
x=1
y=2
z=3

Примечание: ключи в mydict должны быть названы точно так же параметры функции foo. В противном случае он выкинет TypeError:

>>> mydict = {'x':1,'y':2,'z':3,'badnews':9}
>>> foo(**mydict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() got an unexpected keyword argument 'badnews'
46
задан nos 1 March 2010 в 21:30
поделиться

4 ответа

Вы можете передать файловый дескриптор другому процессу через сокеты 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 */
48
ответ дан nos 26 August 2018 в 17:10
поделиться
  • 1
    Обратите внимание, что фактическое числовое значение дескриптора файла в общем случае будет различным в двух процессах. – caf 1 March 2010 в 22:31
  • 2
    Вы можете передать число таким образом. Это не волшебным образом означает, что он будет работать как дескриптор файла в тот же файл на обоих концах. – user207421 12 May 2014 в 09:50
  • 3
    @EJP Идея с SCM_RIGHTS заключается в том, что она будет. Хотя никто не приходит на ум, я уверен, что есть некоторые оговорки. (т. е. концепция работает почти так же, как dup (), но между несвязанными процессами) – nos 12 May 2014 в 11:12

Если оба процесса принадлежат одному и тому же пользователю, то вы можете просто использовать 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: после получения сигнала можно узнать PID отправителя? ".

1
ответ дан kay 26 August 2018 в 17:10
поделиться
  • 1
    Вы имели бы в виду & quot; / proc /% d / fd /% d & quot; в пределах snprintf? – kaiwan 10 July 2017 в 07:01
  • 2
    @kaiwan, да. Исправлено, спасибо! – kay 10 July 2017 в 09:38

Вы можете использовать метод nos, описанный в этом потоке, или (более обычный) способ, передавая его между связанными процессами (обычно родительскими или дочерними), создавая их, разветвленные процессы автоматически получают копию.

Действительно, forked-процессы получают все ваши FD и могут использовать их, если они не закрывают их (что обычно является хорошей идеей).

Поэтому, если родительский forks два ребенка, если они оба имеют файловый дескриптор, который они не закрывали, теперь он разделен (даже если родитель впоследствии закрывает его). Это может быть, например, труба от одного ребенка к другому. Это как перенаправление оболочки подобно

ls -l | more

Работа.

2
ответ дан MarkR 26 August 2018 в 17:10
поделиться

Обратите внимание, что в приведенном выше примере установка переменных при приеме, например:

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;

, не требуется. Вся идея структуры сообщений с заголовками заключается в том, что принимающий сайт не должен знать, что он читает, и может, проверив заголовок (первый), какое сообщение оно и что ожидать.

2
ответ дан Tim Cooper 26 August 2018 в 17:10
поделиться
  • 1
    Хотя вы технически корректны, есть веская причина для указания буфера в этом случае: для отправки сообщения OOB (в этом случае сообщение управления сокета) вам нужно указать непустое сообщение (см. Unix_stream_sendmsg, например [д0] lxr.free-electrons.com/source/net/unix/af_unix.c#L1836 [/ д0]). При получении без iovec Linux будет передавать это сообщение снова и снова. Следовательно, чтобы читать более одного сообщения OOB, вы ДОЛЖНЫ прочитать данные сообщения в какой-то момент. – Michael 5 January 2017 в 19:26
Другие вопросы по тегам:

Похожие вопросы: