进程的通信

通信领域的几个概念:

        单工通信:数据的传送方向为单向的,发送端和接收端都是固定的,后续不可更改【广播:广播是发送端,听的人是接收端】

        半双工通信:数据的传送方向为双向,但不同时,发送端和接收端不固定,但不能同时两端都为发送端或都为接收端【对讲机】

        全双工通信:数据的传送方向为双向且同时(电脑)

进程间通信:两个进程数据交换

1.无名管道:实现交换的第三方的介质,存在在linux内核中,在文件系统中不可见

        是用pipe创建的一个内核文件

 特点:

1.只能用于具有亲缘关系(父子,子孙,兄弟)的进程间的通信,

2.是一种单工通信模式(理论上是双工的,但是通信双方的收发顺序不好控制,通常用作单工)

3.无名管道的数据存放在内存中,管道中的数据读走后就不存在了,无名管道只存在在内核中,在文件系统中不可见

不好用!!!

        

        pipe函数:

#include

//作用:创建无名管道

int pipe(int fd[2]);

//pipefd[2]:数组,fd[0]用来标识读管道文件
                 //fd[1]用来标识,写管道文件(IO函数,read,write)
//参数:有两个整数的数组

//成功返回0,失败返回-1
#include
#include
#include
#define SIZE 30

//无名管道

int main()
{

	//创建无名管道
    //fd[0],fd[1]是文件描述符
	//fd[0]用来标识读出管道文件
	//fd[1]用来标识写入管道文件
	int fd[2]={0};
	if(0!=pipe(fd))
	{
		return -1;
	}
	printf("create piped success\r\n");
	//创建一个子进程
	pid_t pid=-1;
	pid=fork();
	if(pid==-1)
	{
		//进程未创建成功
		return -1;
	}
	char buf[SIZE]={0};
	if(pid==0)
	{
		//进入子进程,write
		
		printf("child process----\r\n");
		strcpy(buf,"child to parent");
		//write(int fd,const void *buf,size_t count)
		//参数1:文件描述符
		//参数2:要写的内存空间的首地址
		//参数3:要写的内容的大小
		write(fd[1],buf,SIZE);
		//printf("buf=%s\r\n",buf);
	}
	if(pid!=0)
	{
		//进入父进程
		printf("parent process----\r\n");
		//read(int fd,void *buf,size_t count)
		//参数1:文件描述符
		//参数2:要读的内存空间的首地址
		//参数3:要读的内容的大小
		read(fd[0],buf,SIZE);
	
		printf("read success,buf=%s\r\n",buf);
	}
	
	return 0;
}

2.有名管道(用于任意进程间的通信)

        有名管道使用mkfifo创建的一个内核文件,用于任意两个进程之间的通信

        管道文件在文件系统中可见
        

 #include 
 #include 

int mkfifo(const char *pathname, mode_t mode);

//作用:创建一个有名管道
//*pathname:是有名管道文件的名称
//mode :文件的权限
//返回值:成功返回0,失败返回-1


//A进程数据传到B进程
A:
    1.mkfifo->有名称
    2.open
    3.write
B:
    1.mkfifo
    2.open
    3.read

特点:

1.有名管道可以用于任意两个进程间的通信

2.可以实现双工通信,是建立在两个管道上的

3.有名管道中的数据存放在内存中,数据读走后就没有了

4.有名管道文件在文件系统中可见,文件大小为0,因为数据存放在内存中

先写后读 

#include
#include
#include
#define SIZE 30

//无名管道

int main()
{

	//创建无名管道
	//fd[0]用来标识读出管道文件
	//fd[1]用来标识写入管道文件
	int fd[2]={0};
	if(0!=pipe(fd))
	{
		return -1;
	}
	printf("create piped success\r\n");
	//创建一个子进程
	pid_t pid=-1;
	pid=fork();
	if(pid==-1)
	{
		//进程未创建成功
		return -1;
	}
	char buf[SIZE]={0};
	if(pid==0)
	{
		//进入子进程,write
		
		printf("child process----\r\n");
		strcpy(buf,"child to parent");
		//write(int fd,const void *buf,size_t count)
		//参数1:文件描述符
		//参数2:要写的内存空间的首地址
		//参数3:要写的内容的大小
		write(fd[1],buf,SIZE);
		//printf("buf=%s\r\n",buf);
	}
	if(pid!=0)
	{
		//进入父进程
		printf("parent process----\r\n");
		//read(int fd,void *buf,size_t count)
		//参数1:文件描述符
		//参数2:要读的内存空间的首地址
		//参数3:要读的内容的大小
		read(fd[0],buf,SIZE);
	
		printf("read success,buf=%s\r\n",buf);
	}
	
	return 0;
}

 先读后写

#include
#include
#include
#include
#include
#include
#include
#define SIZE 20

int main()
{
	//1.1.mkfifoA   
	int ret=-1;
	ret=mkfifo("fifoa",0666);
	//创建文件失败并且该文件不存在
	if(ret < 0 &&EEXIST!=errno)
	{
		printf("error\r\n");
		return -1;//创建文件失败
	}
	//创建文件失败但是该文件存在--》创建文件成功
	printf("1.1:create fifoa ok!----\r\n");
	

	//1.2.mkfifoB  
	ret=mkfifo("fifob",0666);
	//创建文件失败并且该文件不存在
	if(ret < 0 &&EEXIST!=errno)
	{
		printf("error\r\n");
		return -1;//创建文件失败
	}
	//创建文件失败但是该文件存在--》创建文件成功
	printf("1.2:create fifob ok!----\r\n");


	//2.1.open fifoa
	int fdr=open("fifoa",O_RDONLY,0666);
	if(-1 == fdr)
	{
		perror("open error");
		return -1;
	}
	printf("2.1:open fifoa ok!-----\r\n");
	
	//2.2.open fifob
	int fdw=open("fifob",O_WRONLY,0666);
	if(-1 == fdw)
	{
		perror("open error");
		return -1;
	}
	printf("2.2:open fifob ok!-----\r\n");
	
	char buf[SIZE]={0};
	while(1)
	{
		
		//read
		memset(buf,0,SIZE);
		read(fdr,buf,SIZE);
		printf("a->b:%s\r\n",buf);

		
		//write
		memset(buf,0,SIZE);
		fgets(buf,SIZE,stdin);
		write(fdw,buf,SIZE);
	}
	
	//5.close
	close(fdw);
	close(fdr);

	return 0;
}

两个同时运行,可实现通信 

3.信号通信 (唯一一种异步通信方式)

异步:被通信方不知道什么时候通信,

进程:task_struct+4G的虚拟空间

用户空间进程:task_struct+(0G-3G)的虚拟空间

内核空间进程:task_struct+(3G-4G)的虚拟空间

信号:linux操作系统预先定义好了64个信号(操作系统提供)

           kill -l :查看当前系统提供的所有信号

kill -9  进程号:程序员调用,给内核发送SIGKILL信号,让内核杀死指定的进程号的进程

进程的通信_第1张图片

 进程的通信_第2张图片

 用户进程对信号的响应方式:捕获信号,忽略信号,采用默认处理动作

signal (信号,自定义的信号对应的处理函数)--->用来改变信号的默认处理状态

进程的通信_第3张图片

进程的通信_第4张图片 

 实现两个进程的异步通信(信号通信)

     A   收信号进程:要用signal注册信号处理函数,signal ,pause

     B   发信号进程:kill (),

//kill

#include
#include

int kill(pid_t pid,int sig);

//参数1:对方的进程号
//参数2:要发送的信号

同步通信和异步通信:

        同步通信:发送方发数据,接收方收数据,双方需要在很短的时间内完成数据交换,否则会造成一方阻塞

        异步通信:被通信方不知道通信方什么时候和它通信

 

#include 

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

//作用:设置某一信号的动作
//参数1:要处理的信号类型,可以取除了SIGKILL和SIGSTOP之外的任意一种信号
//参数2:描述了与信号关联的动作-->有3个
//返回值:成功返回先前的信号处理函数指针,错误返回-1
SIG_IGN   //表示忽略该信号

进程的通信_第5张图片 

 -->SIG_DFL    //表示恢复对信号的系统默认处理,不写的话此处理默认也是执行系统默认处理
                              

 进程的通信_第6张图片

-->sighandler_t类型的函数指针
:
        typedef void (*sighandler_t)(int);

        sighandler_t signal(int signum, sighandler_t handler);

   此函数必须在signal()被调用前申明,handler(参数2)中为这个函数名,当接收到一个类型为sig的信号时,就执行handler 所指定的函数,(int)signum是传递给它的唯一参数。执行了signal()调用后,进程只要接收到类型为sig的信号,不管其正在执行程序的哪一部分,就立即执行func()函数。当func()函数执行结束后,控制权返回进程被中断的那一点继续执行。 

 进程的通信_第7张图片

 常用的Signal信号:

进程的通信_第8张图片

 进程的通信_第9张图片

 进程的通信_第10张图片

 转载自Signal ()函数详细介绍_怀想天空2010的博客-CSDN博客_signal函数

你可能感兴趣的:(线程进程,linux)