int socketpair(int domain, int type, int protocol, int sockfd[2]); //创建未命名的全双工管道
domain只能为AF_UNIX,也就是限制在本地使用
type可以是SOCK_STREAM或SOCK_DGRAM,SOCK_STREAM相当于创建了双向流管道,管道的每一端都可以write或read,并且两端的数据流对流是分开的
protocol必须是0
sockfd数组返回管道两端的socket描述符
在2.6.27的内核版本后,type支持了SOCK_CLOEXEC(close on exec )和SOCK_NONBLOCK(非阻塞系统描述符)标志,以节省fcntl系统调用
socketpair创建的描述符常用于亲缘进程间通信,如父进程调用了socketpair后,父进程再调用fork出子进程,子进程自动继承了描述符(前提是没有close on exec),那么父子进程就可以用sockfd进行通信。
例子,父进程在sockepair后,再fork出子进程,然后:
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/socket.h>
#include<unistd.h>
#include<iostream>
#include<cstring>
using namespace std;
int main(){
int fd[2];
if(socketpair(AF_UNIX,SOCK_STREAM,0,fd)<0)//父进程调用socketpair创建fd数组
cout<<"socketpair error"<<endl;
pid_t pid;
if((pid=fork())<0)
cout<<"fork error"<<endl;
else if(pid==0){
close(fd[0]);//父进程持有fd[0]端,子进程持有fd[1]端
write(fd[1],"hello parent",strlen("hello parent"));//子进程通过fd[1]向父进程发送消息
char buf[20];
while(read(fd[1],buf,20)==-1);//子进程在fd[1]端等待父进程的消息
buf[13]='\0';
cout<<"child receive: "<<buf<<endl;
}
else{
close(fd[1]);
write(fd[0],"hello child",strlen("hello world"));//父进程通过fd[0]端向子进程发送消息
char buf[20];
while(read(fd[0],buf,20)==-1);//父进程在fd[0]端等待子进程的消息
cout<<"parent receive: "<<buf<<endl;
wait(NULL);
}
return 0;
}
程序输出:
parent receive: hello parent
child receive: hello child
可见socketpair创建的UNIX域套接字可用于亲缘进程间通信(未命名限制了只能在亲缘进程间使用),在nginx中,master进程就利用socketpair创建套接字然后fork出worker进程,这样master进程和worker进程间就可以利用socketpair产生的套接字通信了。