1.1 信号
信号产生的情况:
1. 键盘事件 ctrl + C发出中断信号
2. 软件层面 在程序中调用kill函数发送信号
3. 硬件问题 外设出错或者其他原因收到的信号
4. 内存管理错误
信号的处理方式有三种:
默认:执行信号默认的动作
忽略:忽略信号
捕捉:捕捉信号去执行自定义的动作
可以使用 kill -l 查看当前系统所有信号。
函数原型:
typedef void (*sighandler_t)(int); //声明函数指针类型
sighandler_t signal(int signum, sighandler_t handler);
功能:处理信号(默认、捕捉、忽略)
参数:
signum: 要处理的信号
handler: 要对信号进行的处理动作
SIG_IGN: 忽略
SIG_DFL: 执行默认动作,要么填为信号处理函数
返回值:成功返回信号处理函数的前一个值 失败error
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
/* 信号处理函数 */
void signal_handle(int signum){
if(signum == 2){
printf("catch 2 signal..\n");
}
}
int main(){
//默认--对2号信号执行默认动作
//signal(SIGINT, SIG_DFL);
//捕捉--捕捉到2号信号打印字符串
signal(SIGINT, signal_handle);//会将第一个参数传递给信号处理函数
//signal(2, SIG_IGN);//忽略
while(1);
return 0;
}
1.2 无名管道
借助于内核完成,会在内核创建一根管道,使用函数pipe创建并拿到管道的两端(读端和写端),两端以数组的成员形式存在,分别是两端的文件描述符,对文件描述符操作相当于对管道的读端和写端操作。并且无名管道只能在亲缘进程间通信,管道的大小为64K,如果管道满,再写会阻塞
函数原型:
int pipe(int pipefd[2]);
功能:创建无名管道
参数:
pipefd: 数组,存放管道两端的文件描述符
pipefd[0]: 读端
pipefd[1]: 写端
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(){
//创建无名管道
int pipefd[2];
if(-1 == pipe(pipefd)){
perror("pipe");
exit(EXIT_FAILURE);
}
pid_t cpid;
//创建进程
if(-1 == (cpid = fork())){
perror("fork");
exit(EXIT_FAILURE);
}
if(cpid == 0){ //子进程-写操作
char cbuffer[10] = {0};
while(1){
memset(cbuffer, 0, sizeof(cbuffer));
printf("input > ");
fgets(cbuffer, sizeof(cbuffer), stdin);
cbuffer[strlen(cbuffer)-1] = '\0';
write(pipefd[1], cbuffer, strlen(cbuffer));
if( strncmp("quit", cbuffer, 4) == 0)
break;
}
exit(EXIT_SUCCESS);
}else{ //父进程
char pbuffer[10] = {0};
while(1){
memset(pbuffer, 0, sizeof(pbuffer));
read(pipefd[0], pbuffer, sizeof(pbuffer));
printf("data = %s\n", pbuffer);
if( strncmp("quit", pbuffer, 4) == 0)
break;
}
wait(NULL);
exit(EXIT_SUCCESS);
}
return 0;
}
无名管道读写规则:
1.写端和读端存在,读管道,有多少读多少,管道为空,读阻塞
2.写端和读端存在,写管道,有多少写多少,管道为满,写阻塞
3. 读端不存在,写管道,管道破裂,会发出信号SIGPIPE
4.写端不存在,读管道,有多少读多少,管道为空直接返回
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
void signalHandle(int signum){
printf("管道破裂\n");
}
int main(){
//创建无名管道
int pipefd[2];
if(-1 == pipe(pipefd)){
perror("pipe");
exit(EXIT_FAILURE);
}
//在管道破裂之前就执行捕捉信号的动作
signal(SIGPIPE, signalHandle);
//关闭读端,写操作
close(pipefd[0]);
write(pipefd[1], "hello", 5);
return 0;
}
1.3 有名管道
有名管道可以使用在任意进程间通信,因为有名管道直接创建FIFO类型的管道文件,可供系统中的任意一个进程访问。
函数原型:
int mkfifo(const char *pathname, mode_t mode);
功能:创建有名管道文件
参数:
pathname: 有名管道文件的路径以及名称
mode : 创建管道文件时的权限
返回值:成功0 失败-1
创建管道文件:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
int main(){
//创建管道文件
//创建在Linux操作系统的任意一个能访问到的目录下
//不能创建在共享文件夹中,windows不支持管道文件类型
if(-1 == mkfifo("/home/linux/File_fifo", 0666)){
perror("mkfifo");return -1;
}
getchar();//清除多余字符
system("rm /home/linux/File_fifo -rf");
return 0;
}
写:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(){
//打开管道文件
int fd;
if(-1 == (fd = open("/home/linux/File_fifo", O_RDWR))){
perror("open");return -1;
}
char buffer[10] = {0};
while(1){
memset(buffer, 0, sizeof(buffer));
printf("input > ");
fgets(buffer, sizeof(buffer), stdin);
buffer[strlen(buffer)-1] = '\0';
write(fd, buffer, strlen(buffer));
if( strncmp("quit", buffer, 4) == 0)
break;
}
return 0;
}
读:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(){
//打开管道文件
int fd;
if(-1 == (fd = open("/home/linux/File_fifo", O_RDWR))){
perror("open");return -1;
}
char buffer[10] = {0};
while(1){
memset(buffer, 0, sizeof(buffer));
read(fd, buffer, sizeof(buffer));
printf("data = %s\n", buffer);
if( strncmp("quit", buffer, 4) == 0)
break;
}
return 0;
}