一、无名管道pipe
Linux系统编程——进程间通信:管道(pipe)
无名管道pipe需要注意的几点:
写操作:
1.只要读端不关闭读fd(fds[0]),那么写端就可以写。
如果一个进程退出,或者显式调用close关闭了读端fds[0],那么写入的一端进程,就无法再写了。会阻塞在那里,无论是阻塞写还是非阻塞写。
2. 如果缓冲区满了
如果是阻塞写,会阻塞在那里。
如果fds[1]设置成非阻塞,那么write会立刻返回,返回-1
读操作:
1.如果管道中没有数据,阻塞方式读操作会阻塞
3. 如果写端,read读,分两种情况:
(1)读端关闭了fds[1]的话,读端会立刻返回,读到的len为0.
{
pid = fork();
if (pid == 0) {
sleep(2);
return 0;
}
close(fds[1]);
while (1) {
printf("child begin read ..\n");
ret = read(fds[0], buf, sizeof(buf));
printf("child read ret = %d msg:[%s]\n", ret, buf);
sleep(1);
}
close(fds[0]);
}
root@lipenghui-virtual-machine:/mnt/hgfs/vmshare# ./test
child begin read ..
child read ret = 0 msg:[]
child begin read ..
child read ret = 0 msg:[]
child begin read ..
child read ret = 0 msg:[]
child begin read ..
child read ret = 0 msg:[]
child begin read ..
child read ret = 0 msg:[]
child begin read ..
child read ret = 0 msg:[]
(2)读端未关闭fds[1]的话,读端会阻塞
{
pid = fork();
if (pid == 0) {
sleep(2);
return 0;
}
while (1) {
printf("child begin read ..\n");
ret = read(fds[0], buf, sizeof(buf));
printf("child read ret = %d msg:[%s]\n", ret, buf);
sleep(1);
}
close(fds[0]);
}
root@lipenghui-virtual-machine:/mnt/hgfs/vmshare# ./test
child begin read ..
^C
root@lipenghui-virtual-machine:/mnt/hgfs/vmshare#
二、有名管道fifo
进程间通信-命名管道FIFO
mkfifo创建管道文件权限的问题 文件权限=mode & (~umask)
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
DESCRIPTION
mkfifo() makes a FIFO special file with name pathname. mode specifies the FIFO's permis‐
sions. It is modified by the process's umask in the usual way: the permissions of the cre‐
ated file are (**mode & ~umask**).
root@lipenghui-virtual-machine:/mnt/hgfs/vmshare/process# umask
0022
//000 010 010 取反 111 101 101
//mkfifo("/tmp/fifo2", 0777) 0777 & (~umask) 111 101 101
root@lipenghui-virtual-machine:/mnt/hgfs/vmshare/process# la -al /tmp/fifo2
prwxr-xr-x 1 root root 0 4月 26 09:14 /tmp/fifo2
//mkfifo("/tmp/fifo3", 0722) 0722 & (~umask) 111 000 000
root@lipenghui-virtual-machine:/mnt/hgfs/vmshare/process# ls -al /tmp/fifo3
prwx------ 1 root root 0 4月 26 09:27 /tmp/fifo3
命令行方式使用
root@lipenghui-virtual-machine:/mnt/hgfs/vmshare/process# mkfifo /tmp/fifo2
root@lipenghui-virtual-machine:/mnt/hgfs/vmshare/process# ls -al /tmp/fifo2
prw-r--r-- 1 root root 0 4月 26 09:58 /tmp/fifo2
root@lipenghui-virtual-machine:/mnt/hgfs/vmshare/process# cat /tmp/fifo2
123
root@lipenghui-virtual-machine:/mnt/hgfs/vmshare/process# echo 123 > /tmp/fifo2
cat查看管道文件,会挂起,一直到echo写入。
如果先echo写,那么echo也会挂起,直到cat去读,echo写完毕。
fifo如果一端想写,那么必须另一端以读的方法打开,不然阻塞或者返回fd<0,open失败。
三. sockepair
socketpari的使用范围与pipe一样,可以当作pipe使用,但socketpair的显著特点是全双工通信,socketpair建立的一对套接字中的任意一个都既可以写也可以读。
可以往sv[0]中写,从sv[1]中读;或者从sv[1]中写,从sv[0]中读;
一端往sv[0]中写入后,再从该套接字读时会阻塞,另一端从sv[1]中可以读到消息,然后另一端通过sv[1]写,这端通过sv[0]读到数据。
#include <sys/types.h>
#include <sys/socket.h>
int socketpair(int domain, int type, int protocol, int sv[2]);
socketpair()函数建立一对匿名的已经连接的套接字,其特性由协议族d、类型type、协议protocol决定,建立的两个套接字描述符会放在sv[0]和sv[1]中。socketpair函数参数说明:
第1个参数domain,表示协议族,只能为AF_LOCAL或者AF_UNIX。
第2个参数type,表示协议,可以是SOCK_STREAM或者SOCK_DGRAM。
用SOCK_STREAM建立的套接字对是管道流,与一般的管道相区别的是,套接字对建立的通道是双向的,即每一端都可以进行读写。
第3个参数protocol,表示类型,只能为0。
第4个参数sv[2]是接收代表两个套接口的整数数组。每一个文件描述符代表一个套接口,并且与另一个并没有区别。函数返回值: 如果函数成功,将会返回0值。否则将会返回-1表明创建失败,并且errno来表明特定的错误号。
举个栗子:
1. 进程间通信
int main()
{
int sv[2];
pid_t pid;
char buf1[64] = {0}, buf2[64] = {0};
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv) < 0) return -1;
pid = fork();
if (pid < 0) return -1;
if (pid == 0) {
write(sv[1], "nihao", 5);
read(sv[1], buf2, sizeof(buf2));
printf("child recv msg:%s\n", buf2);
printf("bye bye child\n");
return 0;
}
read(sv[0], buf1, sizeof(buf1));
printf("father recv msg:%s\n", buf1);
write(sv[0], "hello", 5);
printf("bye bye father\n");
return 0;
}
2. 线程间通信
void* theadhandler(void *arg)
{
int sv = *((int*)arg);
char buf2[64] = {0};
write(sv, "nihao", 5);
read(sv, buf2, sizeof(buf2));
printf("child recv msg:%s\n", buf2);
printf("bye bye child\n");
return 0;
}
int main()
{
int sv[2];
char buf1[64] = {0};
pthread_t thread;
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv) < 0) return -1;
if (pthread_create(&thread, NULL, theadhandler, &sv[1]) < 0) return -1;
read(sv[0], buf1, sizeof(buf1));
printf("father recv msg:%s\n", buf1);
write(sv[0], "hello", 5);
printf("bye bye father\n");
sleep(3);
return 0;
}