UNP讲述了三种传递描述符的方法:
1.使用ioctl
2.如果是父子关系进程用socketpair
3.没关系则使用unix socket
这里介绍一下第三种,因为相对复杂繁琐:
UNP里讲述了这个步骤:
1.创建unix stream socket,其中要有一个是bind且在listen的。
2.使用sendmsg与recvmsg接口传送描述符
3.需要注意的是相关的工具宏和struct.具体翻阅14.5节.
下面我自己写的两个示例代码,图一接收文件描述符并输出hello来验证,图二是要一个临时文件作为参数传入,并发送该文件的套接字给图一的进程.值得注意的是,在发送时,该文件描述符的引用计数会增加,因此关闭进程2并不会导致进程1使用此描述符.
extern "C" { #include} int main(int argc, char **argv) { sockaddr_un seraddr; bzero(&seraddr, sizeof(seraddr)); seraddr.sun_family = AF_UNIX; strcpy(seraddr.sun_path, UNIXSTR_PATH); int lisfd = socket(AF_UNIX, SOCK_STREAM, 0); int on = 1; unlink(UNIXSTR_PATH); Bind(lisfd, (SA *)&seraddr, sizeof(seraddr)); Listen(lisfd, LISTENQ); sockaddr_un cliaddr; socklen_t addrlen; int connfd = Accept(lisfd, (SA *)&cliaddr, &addrlen); msghdr msg; iovec iov; msg.msg_name = NULL; msg.msg_namelen = 0; int tmp; iov.iov_base = &tmp; iov.iov_len = sizeof(int); msg.msg_iov = &iov; msg.msg_iovlen = 1; union { cmsghdr cm; char control[CMSG_SPACE(sizeof(int))]; } control_un; msg.msg_control = control_un.control; msg.msg_controllen = sizeof(control_un.control); if (recvmsg(connfd, &msg, 0) < 0) { perror("recvmsg"); } int recvfd = -1; auto cmptr = CMSG_FIRSTHDR(&msg); if (cmptr == NULL) { perror("CMSG"); } if (cmptr->cmsg_type != SCM_RIGHTS) { perror("type"); } recvfd = *((int *)CMSG_DATA(cmptr)); char buf[] = "hello"; printf("the fd: %d ", recvfd); Write(recvfd, buf, strlen(buf) + 1); exit(0); }
extern "C" { #include} int main(int argc, char **argv) { int sndfd = open(argv[1], O_RDWR | O_TRUNC | O_CREAT); printf("the fd: %d", sndfd); sockaddr_un seraddr; bzero(&seraddr, sizeof(seraddr)); seraddr.sun_family = AF_UNIX; strcpy(seraddr.sun_path, UNIXSTR_PATH); int connfd = Socket(AF_UNIX, SOCK_STREAM, 0); Connect(connfd, (SA *)&seraddr, sizeof(seraddr)); msghdr msg; msg.msg_name = NULL; msg.msg_namelen = 0; iovec iov; iov.iov_base = &sndfd; iov.iov_len = sizeof(sndfd); msg.msg_flags = 0; union { cmsghdr cm; char pad[CMSG_SPACE(sizeof(int))]; } control; msg.msg_control = control.pad; msg.msg_controllen = sizeof(control.pad); msg.msg_flags = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; auto cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr->cmsg_len = CMSG_LEN(sizeof(int)); cmsgptr->cmsg_level = SOL_SOCKET; cmsgptr->cmsg_type = SCM_RIGHTS; *(int *)CMSG_DATA(cmsgptr) = sndfd; sendmsg(connfd, &msg, 0); exit(0); }