socketpair是不是只能用在fork的进程间?
时间: 2023-06-24 22:03:11 浏览: 271
是的,socketpair通常用于在父子进程之间创建进程间通信的套接字对。在一个进程中调用socketpair函数会创建两个关联的套接字,其中一个用于读取,另一个用于写入。这两个套接字可以用于在进程之间进行双向通信。而且,由于这两个套接字是相互关联的,所以它们可以在同一进程中使用,但这样使用通常没有意义。
相关问题
介绍socketpair及其使用
socketpair是一组用于创建全双工通信管道的函数。它可以在内核中创建一对已连接的套接字,这对套接字之间可以进行双向通信,类似于管道。
socketpair函数的原型如下:
```c
#include <sys/types.h>
#include <sys/socket.h>
int socketpair(int domain, int type, int protocol, int sv[2]);
```
参数说明:
- domain:地址族,可以是AF_INET(IPv4)、AF_INET6(IPv6)或AF_UNIX(本地套接字)。
- type:套接字类型,可以是SOCK_STREAM(流式套接字)或SOCK_DGRAM(数据报套接字)。
- protocol:协议类型,一般为0,表示自动选择。
- sv:指向套接字文件描述符的数组,其中sv[0]表示第一个套接字,sv[1]表示第二个套接字。
使用socketpair函数创建套接字对后,可以使用fork函数来创建子进程,子进程可以通过套接字与父进程通信,实现进程间通信。
下面是一个简单的例子,演示了socketpair函数的使用:
```c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
int main() {
int sv[2];
char buf[1024];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
perror("socketpair");
return -1;
}
if (fork() == 0) { // 子进程
close(sv[0]);
write(sv[1], "hello from child", 16);
read(sv[1], buf, sizeof(buf));
printf("%s\n", buf);
} else { // 父进程
close(sv[1]);
write(sv[0], "hello from parent", 17);
read(sv[0], buf, sizeof(buf));
printf("%s\n", buf);
}
return 0;
}
```
该例子中创建了一个AF_UNIX域的套接字对,其中父进程向子进程发送了一条消息并等待子进程的回复,子进程读取了父进程发送的消息并回复了一条消息给父进程。运行该程序可以看到如下输出:
```
hello from child
hello from parent
```
可以看到子进程和父进程之间通过socketpair函数创建的套接字进行了双向通信。
用c/c++代码举例说明如何使用socket在进程间传递文件句柄
在 Unix/Linux 系统下,我们可以使用 `sendmsg` 和 `recvmsg` 函数来传递文件句柄。下面是一个简单的示例代码:
#### 发送进程代码
```c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#define CONTROLLEN CMSG_LEN(sizeof(int))
int send_fd(int fd, int fd_to_send)
{
struct iovec iov[1];
struct msghdr msg;
char buf[2]; // 发送任意数据
int ret;
union {
struct cmsghdr cm;
char control[CONTROLLEN];
} control_un;
struct cmsghdr *pcmsg;
iov[0].iov_base = buf;
iov[0].iov_len = 2;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
if (fd_to_send >= 0) {
msg.msg_control = control_un.control;
msg.msg_controllen = CONTROLLEN;
pcmsg = CMSG_FIRSTHDR(&msg);
pcmsg->cmsg_len = CONTROLLEN;
pcmsg->cmsg_level = SOL_SOCKET;
pcmsg->cmsg_type = SCM_RIGHTS;
*(int *)CMSG_DATA(pcmsg) = fd_to_send;
} else {
msg.msg_control = NULL;
msg.msg_controllen = 0;
buf[1] = 0;
}
buf[0] = 0;
if ((ret = sendmsg(fd, &msg, 0)) < 0) {
perror("sendmsg");
}
return ret;
}
```
#### 接收进程代码
```c
int recv_fd(int fd)
{
struct iovec iov[1];
struct msghdr msg;
char buf[2];
int ret;
union {
struct cmsghdr cm;
char control[CONTROLLEN];
} control_un;
struct cmsghdr *pcmsg;
iov[0].iov_base = buf;
iov[0].iov_len = 2;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = control_un.control;
msg.msg_controllen = CONTROLLEN;
if ((ret = recvmsg(fd, &msg, 0)) < 0) {
perror("recvmsg");
return -1;
}
if (buf[0] != 0) {
printf("error: received %d bytes\n", ret);
return -1;
}
if ((pcmsg = CMSG_FIRSTHDR(&msg)) != NULL &&
pcmsg->cmsg_len == CONTROLLEN) {
if (pcmsg->cmsg_level != SOL_SOCKET) {
printf("error: control level != SOL_SOCKET\n");
return -1;
}
if (pcmsg->cmsg_type != SCM_RIGHTS) {
printf("error: control type != SCM_RIGHTS\n");
return -1;
}
return *(int *)CMSG_DATA(pcmsg);
} else {
return -1;
}
}
```
使用示例:
```c
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
int fd[2];
int ret;
char buf[256];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) {
perror("socketpair");
exit(1);
}
int send_fd = open("file.txt", O_RDONLY);
if (send_fd < 0) {
perror("open");
exit(1);
}
if ((ret = fork()) < 0) {
perror("fork");
exit(1);
}
if (ret == 0) { // 子进程
close(fd[0]);
int recv_fd = recv_fd(fd[1]);
if (recv_fd < 0) {
exit(1);
}
printf("received fd: %d\n", recv_fd);
read(recv_fd, buf, 256);
printf("read: %s\n", buf);
close(recv_fd);
exit(0);
} else { // 父进程
close(fd[1]);
send_fd(fd[0], send_fd);
close(send_fd);
waitpid(ret, NULL, 0);
exit(0);
}
}
```
在这个示例中,父进程打开了 `file.txt` 文件,并将其文件描述符通过 `send_fd` 函数发送给了子进程。子进程通过 `recv_fd` 函数接收到了文件描述符,并读取了文件中的内容。注意,这个示例中并没有考虑错误处理,实际应用中需要根据实际情况进行完善。
阅读全文