原文链接:使用 Unix Domain Sockets 在不同进程间传递文件句柄 - shensunbo Blog
我的仓库地址:gitee.com/coderkemi/i…
传递单个句柄
sender
sender.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <fcntl.h>
#define SOCKET_NAME "/tmp/my_socket"
void send_fd(int socket, int fd_to_send) {
const char *str1 = "Hello, ";
struct msghdr msg = {};
struct iovec io = { .iov_base = (void *)str1, .iov_len = 1 };
char control[CMSG_SPACE(sizeof(int))];
msg.msg_iov = &io;
msg.msg_iovlen = 1;
msg.msg_control = control;
msg.msg_controllen = sizeof(control);
struct cmsghdr *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)) = fd_to_send;
if (sendmsg(socket, &msg, 0) == -1) {
perror("sendmsg");
}
}
int main() {
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un server_addr = { .sun_family = AF_UNIX, .sun_path = SOCKET_NAME };
unlink(SOCKET_NAME);
bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
listen(sockfd, 1);
printf("Awaiting connection...\n");
int client_sock = accept(sockfd, NULL, NULL);
printf("Connection accepted!\n");
int file_fd = open("example.txt", O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
send_fd(client_sock, file_fd);
printf("File descriptor sent!\n");
close(file_fd);
close(client_sock);
close(sockfd);
return 0;
}
receiver
receiver.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <fcntl.h>
#define SOCKET_NAME "/tmp/my_socket"
int receive_fd(int socket) {
struct msghdr msg = {};
char buf[1];
struct iovec io = { .iov_base = buf, .iov_len = sizeof(buf) };
char control[CMSG_SPACE(sizeof(int))];
msg.msg_iov = &io;
msg.msg_iovlen = 1;
msg.msg_control = control;
msg.msg_controllen = sizeof(control);
if (recvmsg(socket, &msg, 0) <= 0) {
perror("recvmsg");
return -1;
}
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
return *((int *)CMSG_DATA(cmsg));
}
int main() {
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un server_addr = { .sun_family = AF_UNIX, .sun_path = SOCKET_NAME };
connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
printf("Connected to sender!\n");
int fd_received = receive_fd(sockfd);
if (fd_received != -1) {
printf("File descriptor received: %d\n", fd_received);
// Use the file descriptor (e.g., read/write to the file it points to)
// Don't forget to close it eventually
char buffer[100];
read(fd_received, buffer, sizeof(buffer));
printf("Read from file: %s\n", buffer);
close(fd_received);
}
close(sockfd);
return 0;
}
编译
gcc -o receiver.exe receiver.c
gcc -o sender.exe sender.c
运行
创建 example.txt
quark@quarkpi-ca2:~$ cat example.txt
file123abc
quark@quarkpi-ca2:~$
运行 sender.exe
quark@quarkpi-ca2:~$ ./sender.exe
Awaiting connection...
Connection accepted!
File descriptor sent!
quark@quarkpi-ca2:~$
运行 receiver.exe
quark@quarkpi-ca2:~$ ./receiver.exe
Connected to sender!
File descriptor received: 4
Read from file: file123abc
quark@quarkpi-ca2:~$
传递多个句柄
sender
sender.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#define SOCKET_NAME "/tmp/my_socket"
int main() {
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket");
return 1;
}
struct sockaddr_un server_addr = { .sun_family = AF_UNIX };
strncpy(server_addr.sun_path, SOCKET_NAME, sizeof(server_addr.sun_path) - 1);
unlink(SOCKET_NAME);
if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("bind");
close(sockfd);
return 1;
}
if (listen(sockfd, 1) == -1) {
perror("listen");
close(sockfd);
return 1;
}
printf("Awaiting connection...\n");
int client_sock = accept(sockfd, NULL, NULL);
if (client_sock == -1) {
perror("accept");
close(sockfd);
return 1;
}
printf("Connection accepted!\n");
int file_fd = open("example.txt", O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
int file_fd2 = open("log1.txt", O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
int file_fd3 = open("log2.txt", O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
int file_fd4 = open("log3.txt", O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
char dummy_data = 'X';
struct iovec io = { .iov_base = &dummy_data, .iov_len = 1 };
char cmsgbuf[CMSG_SPACE(sizeof(int) * 4)];
struct msghdr msg = {};
msg.msg_iov = &io;
msg.msg_iovlen = 1;
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int) * 4);
int *fdptr = (int *)CMSG_DATA(cmsg);
fdptr[0] = file_fd;
fdptr[1] = file_fd2;
fdptr[2] = file_fd3;
fdptr[3] = file_fd4;
printf("File descriptors to send: %d %d %d %d\n", file_fd, file_fd2, file_fd3, file_fd4);
if (sendmsg(client_sock, &msg, 0) == -1) {
perror("sendmsg");
fprintf(stderr, "errno: %d\n", errno);
} else {
printf("File descriptors sent successfully!\n");
}
close(file_fd);
close(file_fd2);
close(file_fd3);
close(file_fd4);
close(client_sock);
close(sockfd);
return 0;
}
receiver
receiver.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <fcntl.h>
#define SOCKET_NAME "/tmp/my_socket"
int main() {
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
// struct sockaddr_un server_addr = { .sun_family = AF_UNIX, .sun_path = SOCKET_NAME };
struct sockaddr_un server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sun_family = AF_UNIX;
strncpy(server_addr.sun_path, SOCKET_NAME, sizeof(server_addr.sun_path) - 1);
if(0 != connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr))){
printf("connect error!\n");
return -1;
}
printf("Connected to sender!\n");
// int fd_received = receive_fd(sockfd);
struct msghdr msg = {};
char buf[1];
struct iovec io = { .iov_base = buf, .iov_len = sizeof(buf) };
char control[CMSG_SPACE(sizeof(int) * 4)];
msg.msg_iov = &io;
msg.msg_iovlen = 1;
msg.msg_control = control;
msg.msg_controllen = sizeof(control);
if (recvmsg(sockfd, &msg, 0) <= 0) {
perror("recvmsg");
return -1;
}
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
int* fdptr = ((int *)CMSG_DATA(cmsg));
printf("File descriptor received: %d %d %d %d\n", fdptr[0], fdptr[1], fdptr[2], fdptr[3]);
// Use the file descriptor (e.g., read/write to the file it points to)
// Don't forget to close it eventually
char buffer[100];
read(fdptr[0], buffer, sizeof(buffer));
printf("Read from file 0: %s\n", buffer);
close(fdptr[0]);
read(fdptr[1], buffer, sizeof(buffer));
printf("Read from file 1: %s\n", buffer);
close(fdptr[1]);
read(fdptr[2], buffer, sizeof(buffer));
printf("Read from file 2: %s\n", buffer);
close(fdptr[2]);
read(fdptr[3], buffer, sizeof(buffer));
printf("Read from file 3: %s\n", buffer);
close(fdptr[3]);
close(sockfd);
return 0;
}
编译
gcc -o receiver.exe receiver.c
gcc -o sender.exe sender.c
运行
创建 example.txt
quark@quarkpi-ca2:~$ cat example.txt
file123abc
quark@quarkpi-ca2:~$
创建 log1.txt
quark@quarkpi-ca2:~$ cat log1.txt
11111
quark@quarkpi-ca2:~$
创建 log2.txt
quark@quarkpi-ca2:~$ cat log2.txt
22222
quark@quarkpi-ca2:~$
创建 log3.txt
quark@quarkpi-ca2:~$ cat log3.txt
33333
quark@quarkpi-ca2:~$
运行 sender.exe
quark@quarkpi-ca2:~$ ./sender.exe
Awaiting connection...
Connection accepted!
File descriptors to send: 5 6 7 8
File descriptors sent successfully!
quark@quarkpi-ca2:~$
运行 receiver.exe
quark@quarkpi-ca2:~$ ./receiver.exe
Connected to sender!
File descriptor received: 4 5 6 7
Read from file 0: file123abc
Read from file 1: 11111
3abc
Read from file 2: 22222
3abc
Read from file 3: 33333
3abc
quark@quarkpi-ca2:~$