非阻塞IO,纪录锁,系统V流机制,I/O多路转接(select/poll),readv和writev函数以及存储 映射IO(mmap),这些统称为高级IO。
pipe用来创建管道,但是单个管道只能单向通信,⼀端用于读,⽽而另一端用于写。如果要实现进程双向通信,必须创建一对管道。
而socketpair则可以⽤用来创建双向通 信的管道,
头文件:
#include
#include
原型:
int socketpair(int d,int protocol, int type, int sv[2]);
参数介绍:
socketpair()函数建立一对匿名的已经连接的套接字,其特性由协议族d、类型type、协议protocol决定,建立的两个套接字描述符会放在sv[0]和sv[1]中。
第1个参数d,表示协议族,只能为AF_LOCAL或者AF_UNIX;
第2个参数type,表示类型,只能为0。
第3个参数protocol,表示协议,可以是SOCK_STREAM或者SOCK_DGRAM。用SOCK_STREAM建立的套接字对是管道流,与一般的管道相区别的是,套接字对建立的通道是双向的,即每一端都可以进行读写。参数sv,用于保存建立的套接字对。
socketpair创建了一对无名的套接字描述符(只能在AF_UNIX域中使用),描述符存储于一个二元数组,. fd[2] .这对套接字可以进行双工通信,每一个描述符既可以读也可以写。这个在同一个进程中也可以进行通信,向fd[0]中写入,就可以从fd[1]中读取(只能从s[1]中读取),也可以在fd[1]中写入,然后从fd[0]中读取;但是,若没有在0端写入,而从1端读取,则1端的读取操作会阻塞,即使在1端写入,也不能从1读取,仍然阻塞;反之亦然……
#include
#include
#include
#include
#include
#include
#include
#include
int main()
{
int fd[2];
int w,r;
char * string = "hello world\n";
char * buf = (char*)calloc(1 , 100);
pid_t pid = fork();
if( socketpair(AF_LOCAL, SOCK_STREAM, 0, fd) == -1 )
{
perror("socketpair:");
return 1;
}
if( pid > 0 )
{
//father
printf("I am your father!\n");
close(fd[1]);
if( ( w = write(fd[0] , string , strlen(string) ) ) < 0 )
{
perror("write\n");
return 2;
}
}else if(pid == 0)
{
//child
printf("Fork child process successed\n");
printf("I am a child!\n");
close(fd[0]);
}
else
{
perror("fork\n");
return 3;
}
if( (r = read(fd[1], buf , 100)) < 0)
{
perror("read!\n");
return 4;
}
printf("Pid %d read string in same process : %s \n",getpid(),buf);
printf("Test successed , %d\n",getpid());
return 0;
}
若fork子进程,然后在父进程关闭一个描述符fd[1] ,在子进程中再关闭另一个 fd[0] ,则可以实现父子进程之间的双工通信,两端都可读可写;当然,仍然遵守和在同一个进程之间工作的原则,一端写,在另一端读取;
具体实现如下:
#include
#include
#include
#include
#include
#include
#include
int main()
{
int fd[2];
int ret = socketpair(PF_LOCAL, SOCK_STREAM, 0, fd);
if(ret < 0)
{
perror("socketpair:");
return 1;
}
pid_t id = fork();
if(id == 0)
{
//child
char* buf = "hello, I am a child\n";
close(fd[0]);
while(1)
{
write(fd[1], buf, sizeof(buf));
read(fd[1], buf,sizeof(buf));
sleep(1);
printf("child : %s\n", buf);
}
}
else if(id > 0)
{
//father
char* buf = "I am your father\n";
close(fd[1]);
while(1)
{
read(fd[0], buf, sizeof(buf));
printf("father : %s\n", buf);
write(fd[0], buf, sizeof(buf));
}
}
else
{
perror("fork");
return 2;
}
return 0;
}
以上代码中在父子进程之间各关闭了一个描述符,则在父进程写可从子进程读取,反之若子进程写,父进程同样可以读取;
在父子进程中都不close(fd[1]),也就是保持两个读端,则父进程能够读到string串,但子进程读取空串,或者子进程先读了数据,父进程阻塞于read操作!
之所以子进程能读取父进程的string,是因为fork时,子进程继承了父进程的文件描述符的,同时也就得到了一个和父进程指向相同文件表项的指针;若父子进程均不关闭读端,因为指向相同的文件表项,这两个进程就有了竞争关系,争相读取这个字符串.父进程read后将数据转到其应用缓冲区,而子进程就得不到了,只有一份数据拷贝(若将父进程阻塞一段时间,则收到数据的就是子进程了,已经得到验证,让父进程sleep(3),子进程获得string,而父进程获取不到而是阻塞)