进程间通信1: 管道

一、无名管道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;	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值