通信领域的几个概念:
单工通信:数据的传送方向为单向的,发送端和接收端都是固定的,后续不可更改【广播:广播是发送端,听的人是接收端】
半双工通信:数据的传送方向为双向,但不同时,发送端和接收端不固定,但不能同时两端都为发送端或都为接收端【对讲机】
全双工通信:数据的传送方向为双向且同时(电脑)
进程间通信:两个进程数据交换
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信号,让内核杀死指定的进程号的进程
用户进程对信号的响应方式:捕获信号,忽略信号,采用默认处理动作
signal (信号,自定义的信号对应的处理函数)--->用来改变信号的默认处理状态
实现两个进程的异步通信(信号通信)
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 //表示忽略该信号
-->SIG_DFL //表示恢复对信号的系统默认处理,不写的话此处理默认也是执行系统默认处理
-->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()函数执行结束后,控制权返回进程被中断的那一点继续执行。
常用的Signal信号:
转载自Signal ()函数详细介绍_怀想天空2010的博客-CSDN博客_signal函数