introduce
Note: 句柄通过
msg_control
消息来发送,但是msg_iov
仍然需要正确填充,不然会报错,可以随便填充一个字符
- 发送一个描述符会使描述符的引用计数加1,意味着即使在接收进程调用recvmsg之前,发送进程关闭了该描述符,对于接收进程他任然保持打开状态
- 在接收进程中会创建一个新的描述符,所以发送进程和接收进程的描述符是不相等的
单个句柄
sender
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#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);
std::cout << "Awaiting connection..." << std::endl;
int client_sock = accept(sockfd, NULL, NULL);
std::cout << "Connection accepted!" << std::endl;
int file_fd = open("example.txt", O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
send_fd(client_sock, file_fd);
std::cout << "File descriptor sent!" << std::endl;
close(file_fd);
close(client_sock);
close(sockfd);
return 0;
}
receiver
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#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));
std::cout << "Connected to sender!" << std::endl;
int fd_received = receive_fd(sockfd);
if (fd_received != -1) {
std::cout << "File descriptor received: " << fd_received << std::endl;
// 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));
std::cout << "Read from file: " << buffer << std::endl;
close(fd_received);
}
close(sockfd);
return 0;
}
句柄数组
sender
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <iostream>
#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;
}
std::cout << "Awaiting connection..." << std::endl;
int client_sock = accept(sockfd, NULL, NULL);
if (client_sock == -1) {
perror("accept");
close(sockfd);
return 1;
}
std::cout << "Connection accepted!" << std::endl;
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;
std::cout << "File descriptors to send: " << file_fd << " "
<< file_fd2 << " " << file_fd3 << " " << file_fd4 << std::endl;
if (sendmsg(client_sock, &msg, 0) == -1) {
perror("sendmsg");
std::cerr << "errno: " << errno << std::endl;
} else {
std::cout << "File descriptors sent successfully!" << std::endl;
}
close(file_fd);
close(file_fd2);
close(file_fd3);
close(file_fd4);
close(client_sock);
close(sockfd);
return 0;
}
receiver
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <iostream>
#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 };
if(0 != connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr))){
std::cout << "connect error!" << std::endl;
return -1;
}
std::cout << "Connected to sender!" << std::endl;
// 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));
std::cout << "File descriptor received: " << fdptr[0] <<" "
<< fdptr[1] <<" " << fdptr[2] <<" " << fdptr[3] << std::endl;
// 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));
std::cout << "Read from file 0: " << buffer << std::endl;
close(fdptr[0]);
read(fdptr[1], buffer, sizeof(buffer));
std::cout << "Read from file 1: " << buffer << std::endl;
close(fdptr[1]);
read(fdptr[2], buffer, sizeof(buffer));
std::cout << "Read from file 2: " << buffer << std::endl;
close(fdptr[2]);
read(fdptr[3], buffer, sizeof(buffer));
std::cout << "Read from file 3: " << buffer << std::endl;
close(fdptr[3]);
close(sockfd);
return 0;
}