目录
进程间通信机制:
unix继承:管道、信号
system V IPC对象:共享内存、消息队列、信号灯集
套接字
1、管道
管道分为无名管道和有名管道 -- 区别在于创建的管道能否在文件系统中可见
(1)无名管道
特点:
1、在创建之后在文件系统中不可见
2、以半双工的方式进行通信
3、拥有固定的读端和写端
4、只能用于具有亲缘关系的进程间通信
1)无名管道的创建 --pipe()
#include <unistd.h>
int pipe(int pipefd[2]);
参数:
pipefd:存放无名管道读端和写端的数组首地址
pipefd[0] -- 读端
pipefd[1] -- 写端
返回值:
成功返回0,失败返回-1
练习:在一个进程中创建一个子进程,子进程从键盘获取数据,父进程打印输出
代码示例:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int fd[2] = {0};//定义无名管道读写端的数组
int ret = pipe(fd);//创建无名管道
if(ret < 0)
{
perror("pipe");
exit(-1);
}
pid_t pid = fork();
if(pid < 0)
{
perror("fork");
exit(-1);
}
if(pid == 0)//子进程
{
while(1)
{
char buf[64] = {0};
fgets(buf,64,stdin);
buf[strlen(buf)-1] = '\0';
write(fd[1],buf,strlen(buf));
}
exit(0);
}
else//父进程
{
while(1)
{
char buf1[64] = {0};
memset(buf1,0,64);
read(fd[0],buf1,64);
printf("%s\n",buf1);
}
}
wait(NULL);
exit(0);
return 0;
}
运行结果:
2)无名管道的读写特性
读特性:
写端存在:如果管道有数据,返回读到的字节数
如果管道无数据,阻塞
写端不存在:如果管道有数据,返回读到的字节数
如果管道无数据,返回0
写特性:
读端存在:如果管道有空间,返回写入的字节数
如果管道无空间,阻塞,直到有空间为止
读端不存在:
无论管道是否有空间,管道破裂(向进程发送管道破裂信号,结束进程)
练习:1、计算无名管道空间大小
2、验证管道破裂
代码示例:
1、
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int fd[2];
int ret = pipe(fd);
if(ret < 0)
{
perror("pipe");
exit(-1);
}
int size = 0,m = 0;
while(1)
{
char buf[1024] = {0};
size_t m = write(fd[1],buf,1024);//往管道里写数据,返回字节数
size = size + m;
printf("%d\n",size);
}
return 0;
}
2、
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
int main(int argc, char *argv[])
{
int pfd[2] = {0};
int ret = pipe(pfd); //创建无名管道
if(ret < 0)
{
perror("pipe");
exit(-1);
}
close(pfd[0]); //关闭无名管道的读端
pid_t pid = fork(); //创建子进程
if(pid == 0)
{
write(pfd[1], "hello", 5);
sleep(5);
}
else
{
int status;
wait(&status);
printf("%d %d %d\n", WIFEXITED(status),WIFSIGNALED(status),WTERMSIG(status));
exit(0);
}
return 0;
}
运行结果:
(2)、有名管道
有名管道创建之后会在文件系统中以管道文件的形式存在
有名管道可以用于任意两个进程之间的通信,没有固定的读端和写端
(1)有名管道的创建 -- mkfifo
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
参数:
pathname:创建管道文件的文件名
mode:创建管道文件的权限
返回值:
成功返回0,失败返回-1
练习:创建一个有名管道,一个进程向管道中输入数据,另一个进程输出数据
1、创建有名管道
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int ret = mkfifo("fifo", 0664);
if(ret < 0)
{
perror("mkfifo");
exit(-1);
}
return 0;
}
2、创建进程
进程1:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int fd = open("fifo", O_RDONLY);
if(fd < 0)
{
perror("open");
exit(-1);
}
printf("open fifo ok!\n");
char buf[64] = {0};
while(1)
{
memset(buf, 0, 64);
read(fd, buf, 64);
printf("%s\n", buf);
}
close(fd);
return 0;
}
进程2:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int fd = open("fifo", O_WRONLY);
if(fd < 0)
{
perror("open");
exit(-1);
}
printf("open fifo ok!\n");
char buf[64] = {0};
while(1)
{
fgets(buf, 64, stdin);
buf[strlen(buf)-1] = '\0';
write(fd, buf, strlen(buf));
}
close(fd);
return 0;
}
2、信号
信号:是中断在软件层次上的一种模拟
信号的处理方式:
默认处理
忽略
捕获信号
(1)常用信号
(2)信号相关指令
kill -l :查看当前系统中的所有信号
kill -信号编号 进程号:向指定进程发送对应编号的信号
例:
kill -9 1234:向进程1234发送信号9
kill -9 -1234:向进程组1234发送信号9
kill -9 -1 :向除了init进程以外的其他所有进程发送信号9
(3)信号相关接口函数 -- kill
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
参数:
pid:指定进程号
sig:指定信号
返回值:
成功返回0,失败返回-1;
-------------------------------------------------
#include <signal.h>
int raise(int sig);
参数:
sig:指定信号
返回值:
成功返回0,失败返回非零值
(4)定时器
定时时间到时,当前进程会接受到编号为14的信号 -- SIGARLM
一个进程中最多只能存在一个定时器
定时器相关函数 -- alarm
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
参数:
seconds:定时秒数
返回值:
成功返回0或者上个定时器定时剩余的时间
-------------------------------------------------
#include <unistd.h>
int pause(void);
功能:阻塞在当前位置,等待定时结束
(5)捕获信号 -- signal
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
参数:
signum:指定信号
handler:信号处理函数
SIG_IGN:选择以忽略方式处理指定信号
SIG_DFL:选择以默认方式处理指定信号
练习:创建一个子进程,子进程结束时,父进程提示子进程退出信息
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
void func(int num);
int main(int argc, char *argv[])
{
pid_t pid = fork();
if(pid == 0)
{
printf("aaaaaaaa\n");
exit(0);
}
else
{
signal(17, func);
while(1)
{
printf("bbbbbbbbbbb\n");
sleep(1);
}
}
return 0;
}
void func(int num)
{
printf("child leave!\n");
raise(9);
}