在Linux中,进程可以通过多种方式共享文件描述符。以下是一些常见的方法:
fork() 系统调用当一个进程调用 fork() 创建子进程时,子进程会继承父进程的所有文件描述符。这意味着子进程和父进程将共享相同的文件描述符表,指向相同的文件表项。
#include <stdio.h>
#include <unistd.h>
int main() {
int fd = open("example.txt", O_RDONLY);
if (fd == -1) {
perror("open");
return 1;
}
pid_t pid = fork();
if (pid == -1) {
perror("fork");
close(fd);
return 1;
} else if (pid == 0) {
// 子进程
printf("Child process: fd = %d\n", fd);
close(fd); // 子进程关闭文件描述符
} else {
// 父进程
printf("Parent process: fd = %d\n", fd);
close(fd); // 父进程关闭文件描述符
}
return 0;
}
dup() 和 dup2() 系统调用dup() 和 dup2() 系统调用可以用于复制文件描述符。dup() 返回一个新的文件描述符,指向与现有文件描述符相同的文件表项。dup2() 可以将一个文件描述符重定向到另一个文件描述符。
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
int fd = open("example.txt", O_RDONLY);
if (fd == -1) {
perror("open");
return 1;
}
int fd2 = dup(fd);
if (fd2 == -1) {
perror("dup");
close(fd);
return 1;
}
printf("Original fd: %d\n", fd);
printf("Duplicated fd: %d\n", fd2);
close(fd); // 关闭原始文件描述符
close(fd2); // 关闭复制的文件描述符
return 0;
}
socketpair() 系统调用socketpair() 系统调用可以创建一对相互连接的套接字描述符,这些套接字描述符可以在进程间共享。
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
int main() {
int sockets[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) {
perror("socketpair");
return 1;
}
printf("Socket 1: %d\n", sockets[0]);
printf("Socket 2: %d\n", sockets[1]);
close(sockets[0]);
close(sockets[1]);
return 0;
}
pipe() 系统调用pipe() 系统调用可以创建一个管道,管道的两个端点可以作为文件描述符在进程间共享。
#include <stdio.h>
#include <unistd.h>
int main() {
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe");
return 1;
}
printf("Read end of pipe: %d\n", pipefd[0]);
printf("Write end of pipe: %d\n", pipefd[1]);
close(pipefd[0]);
close(pipefd[1]);
return 0;
}
sendmsg() 和 recvmsg() 系统调用sendmsg() 和 recvmsg() 系统调用可以用于在进程间传递文件描述符。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/uio.h>
int main() {
int sockets[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) {
perror("socketpair");
return 1;
}
char buf[] = "Hello, World!";
struct msghdr msg;
struct iovec iov;
char cmsgbuf[CMSG_SPACE(sizeof(int))];
struct cmsghdr *cmsg;
iov.iov_base = buf;
iov.iov_len = strlen(buf);
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
*(int *)CMSG_DATA(cmsg) = sockets[1];
if (sendmsg(sockets[0], &msg, 0) == -1) {
perror("sendmsg");
close(sockets[0]);
close(sockets[1]);
return 1;
}
close(sockets[0]);
char recvbuf[1024];
iov.iov_base = recvbuf;
iov.iov_len = sizeof(recvbuf);
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
if (recvmsg(sockets[1], &msg, 0) == -1) {
perror("recvmsg");
close(sockets[1]);
return 1;
}
printf("Received message: %s\n", recvbuf);
close(sockets[1]);
return 0;
}
这些方法可以帮助你在Linux进程间共享文件描述符。选择哪种方法取决于你的具体需求和应用场景。