一、匿名管道(PiPe)



cpp
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>
int main(int argc, char const *argv[])
{
pid_t cpid;
int pipefd[2];
//将程序传递进来的第一个命令行参数 通过管道传输给子进程
if (argc !=2)
{
fprintf(stderr,"%s:请填写需要传递的信息\n",argv[0]);
exit(EXIT_FAILURE);
}
//创建管道
int pipeR = pipe(pipefd);
if (pipeR == -1)
{
perror("pipe");
exit(EXIT_FAILURE);
}
//复制父子进程
cpid = fork();
if (cpid == -1)
{
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0)
{
//子进程 读取管道的数据 打印到控制台
//关闭写功能
close(pipefd[1]);
char str[1024]={0};
sprintf(str,"新学员%d接收信息\n",getpid());
write(STDOUT_FILENO,&str,sizeof(str));
char buf;
while (read(pipefd[0],&buf,1)>0)
{
write(STDOUT_FILENO,&buf,1);
}
write(STDOUT_FILENO,"\n",1);
//关闭读功能
close(pipefd[0]);
_exit(EXIT_SUCCESS);
}
else
{
//父进程 写入管道数据 提供给子进程读
//先关闭读功能
close(pipefd[0]);
//将数据写入到管道中
printf("老学员%d对新学员%d传递信息\n",getpid(),cpid);
write(pipefd[1],argv[1],strlen(argv[1]));
//关闭写功能
close(pipefd[1]);
waitpid(cpid,NULL,0);
exit(EXIT_SUCCESS);
}
return 0;
}
makefile
cpp
unnamed_pipe_test:unnamed_pipe_test.c
-$(CC) -o $@ $^
-./$@ "test"
-rm ./$@



二、有名管道

cpp
//fifo_write.cpp内容
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<errno.h>
int main(int argc, char const *argv[])
{
int fd;
//有名管道创建完成之后 后续是可以重复使用的 不推荐重复使用 推荐每次用完之后释放
char*pipe_path="/home/lxl/process_test/temp/myfifo";
int fifoR=mkfifo(pipe_path,0664);
if (fifoR!=0)
{
perror("mkfifo");
if (errno != 17)//文件创建失败的时候退出
{
exit(EXIT_FAILURE);
}
}
//对有名管道的特殊文件 创建fd
fd = open(pipe_path,O_WRONLY);
if (fd == -1)
{
perror("open");
exit(EXIT_FAILURE);
}
char buf[100];
size_t read_num;
//读取控制台数据写入到管道中
while ((read_num = read(STDIN_FILENO,buf,100))>0)
{
write(fd,buf,read_num);
}
if(read_num < 0)
{
perror("read");
close(fd);
exit(EXIT_FAILURE);
}
printf("发送数据到管道完成,进程终止\n");
close(fd);
//释放管道
//清除对应的特殊文件
if (unlink(pipe_path)==-1)
{
perror("unlink");
}
return 0;
}
cpp
//fifo_read.cpp内容
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<errno.h>
int main(int argc, char const *argv[])
{
int fd;
char*pipe_path="/home/lxl/process_test/temp/myfifo";;
//对有名管道的特殊文件 创建fd
fd = open(pipe_path,O_RDONLY);
if (fd == -1)
{
perror("open");
exit(EXIT_FAILURE);
}
char buf[100];
size_t read_num;
//读取管道数据写入到控制台
while ((read_num = read(fd,buf,100))>0)
{
write(STDOUT_FILENO,buf,read_num);
}
if(read_num < 0)
{
perror("read");
close(fd);
exit(EXIT_FAILURE);
}
printf("接收管道数据完成,进程终止\n");
close(fd);
return 0;
}
makefile
cpp
fifo_write:fifo_write.c
-$(CC) -o $@ $^
fifo_read:fifo_read.c
-$(CC) -o $@ $^
三、共享内存










测试例程
展示如何使用mmap在父子进程之间共享信息
cpp
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
#include<string.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/types.h>
int main(int argc, char const *argv[])
{
int fd;
char *share;
//1、创建一个共享内存对象
char shm_name[100]={0};
sprintf(shm_name,"/letter%d",getpid());
fd=shm_open(shm_name,O_RDWR | O_CREAT,0664);
if (fd < 0)
{
perror("shm_open");
exit(EXIT_FAILURE);
}
//2、设置共享内存对象大小
ftruncate(fd,1024);
//3、内存映射
share=mmap(NULL,1024,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
if (share == MAP_FAILED)
{
perror("mmap");
exit(EXIT_FAILURE);
}
//映射完成之后,关闭fd连接,不是释放
close(fd);
//4、使用内存映射实现进程间的通讯
pid_t pid = fork();
if (pid < 0)
{
perror("fork");
exit(EXIT_FAILURE);
}
if (pid==0)
{
//子进程
strcpy(share,"你是个好人\n");
printf("新学员%d完成回信\n",getpid());
}
else
{
//父进程
sleep(1);
waitpid(pid,NULL,0);
printf("老学员%d收到新学员%d的回信:%s",getpid(),pid,share);
//5、释放映射区
int re=munmap(share,1024);
if (re==-1)
{
perror("munamp");
exit(EXIT_FAILURE);
}
}
//释放共享内存对象
shm_unlink(shm_name);
return 0;
}
cpp
shared_memory:shared_memory.c
-$(CC) -o $@ $^ -lrt
-./$@
-rm ./$@



四、消息队列



1、相关系统调用
(1)mq_open()





(2)mq_timedsend()



(3)mq_timedrecceive() 

(4)mq_unlink()


(5)clock_gettime()

2、父子进程间通信测试例程
cpp
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<mqueue.h>
#include<time.h>
#include<stdlib.h>
int main(int argc, char const *argv[])
{
//创建消息队列
struct mq_attr attr;
//有用的参数,表示消息队列的容量
attr.mq_maxmsg=10;
attr.mq_msgsize=100;
//被忽略的消息,在创建消息队列的时候用不到
attr.mq_flags=0;
attr.mq_curmsgs=0;
char *mq_name="/father_son_mq";
mqd_t mqdes= mq_open(mq_name,O_RDWR|O_CREAT,0664,&attr);
if (mqdes == (mqd_t)-1)
{
perror("mq_open");
exit(EXIT_FAILURE);
}
//创建父子进程
pid_t pid =fork();
if (pid<0)
{
perror("fork");
exit(EXIT_FAILURE);
}
if (pid == 0)
{
//子进程 等待接收消息队列中的消息
char buf_receive [100];
struct timespec time_info;
for (int i = 0; i < 10; i++)
{
//清空buf_receive
memset(buf_receive,0,100);
//设置接收数据的等待时间
clock_gettime(0,&time_info);
time_info.tv_sec += 5;
//接收消息队列的数据 打印到控制台
int receiveR = mq_timedreceive(mqdes,buf_receive,100,0,&time_info);
if (receiveR == -1)
{
perror("mq_timedreceive报错");
}
printf("子进程接收到第%d消息:%s\n",i+1,buf_receive);
}
}
else
{
//父进程 发送消息到消息队列中
char buf_send[100];
struct timespec time_info;
for (int i = 0; i < 10; i++)
{
//清空处理buf_send
memset(buf_send,0,100);
sprintf(buf_send,"父进程的第%d次发送消息\n",(i+1));
//获取当前的具体时间
clock_gettime(0,&time_info);
time_info.tv_sec += 5;
//发送消息
int sendR=mq_timedsend(mqdes,buf_send,100,0,&time_info);
if (sendR == -1)
{
perror("mq_timedsend");
}
printf("父进程发送一条消息,休眠1s\n");
sleep(1);
}
}
//最终不管是父进程还是子进程都需要释放消息队列的饮用
close(mqdes);
//清除消息队列只需要执行一次
if(pid>0)
{
mq_unlink(mq_name);
}
return 0;
}
makefile
cpp
father_son_mq_test:father_son_mq_test.c
-$(CC) -o $@ $^ -lrt
-./$@
-rm ./$@
3、非父子进程通信案例
我们创建两个进程:生产者和消费者,前者从控制台接收数据并写入消息i队列,后者从消息队列接收数据并打印到控制台。
cpp
//producer.cpp内容
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<mqueue.h>
#include<string.h>
#include<time.h>
#include<sys/stat.h>
int main(int argc, char const *argv[])
{
//创建消息队列
char*mq_name="/producer";
struct mq_attr atrr;
atrr.mq_maxmsg=10;
atrr.mq_msgsize=100;
atrr.mq_flags=0;
atrr.mq_curmsgs=0;
mqd_t mqdes = mq_open(mq_name,O_RDWR|O_CREAT,0664,&atrr);
if (mqdes == (mqd_t)-1)
{
perror("mq_open");
exit(EXIT_FAILURE);
}
char buf_write[100];
struct timespec time_info;
while(1)//循环挂起 一直读取控制台消息
{
//清除缓存区
memset(buf_write,0,100);
//读取控制台消息
ssize_t readR= read(STDIN_FILENO,buf_write,100);
clock_gettime(0,&time_info);
time_info.tv_sec += 5;
//如果报错
if (readR == -1)
{
perror("read");
continue;
}
else if(readR == 0)
{
//如果从控制台收到停止发送的消息
//ctrl + d 关闭控制台输入
printf("EOF,exit...\n");
char eof=EOF;
//将EOF当作一条消息发送到消息队列
int sendR = mq_timedsend(mqdes,&eof,1,0,&time_info);
if (sendR == -1)
{
perror("mq_timedsend");
}
break;
}
else
{
//正常读取控制台信息
int sendR = mq_timedsend(mqdes,&buf_write,100,0,&time_info);
if (sendR == -1)
{
perror("mq_timedsend");
continue;
}
printf("从控制台读取到消息,已经发送给消息队列\n");
}
}
//释放消息队列的引用
close(mqdes);
//清除消息队列------在消费者那里清除比较好
//mq_unlink(mq_name);
return 0;
}
cpp
//comsumer.cpp内容
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#include<mqueue.h>
#include<time.h>
#include<sys/stat.h>
int main(int argc, char const *argv[])
{
//打开生产者消息队列
char *mq_name="/producer";
mqd_t mqdsp = mq_open(mq_name,O_RDWR);
if (mqdsp == (mqd_t)-1)
{
perror("mq_open");
exit(EXIT_FAILURE);
}
char buf_receive[100];
struct timespec time_info;
while (1)
{
//清空接收缓存区
memset(buf_receive,0,100);
clock_gettime(0,&time_info);
time_info.tv_sec += 5;
int recR = mq_timedreceive(mqdsp,&buf_receive,100,0,&time_info);
if (recR == -1)
{
perror("mq_timedreceive");
continue;
}
else
{
//正常接收信息
if(buf_receive[0] == EOF)//读到消息队列信息末尾
{
printf("接收生产者信息结束,exit...\n");
break;
}
else
{
printf("接收生产者的信息:%s\n",buf_receive);
}
}
}
//释放消息队列的引用
close(mqdsp);
//清除消息队列
mq_unlink(mq_name);
return 0;
}
makefile
cpp
producer:producer.c
-$(CC) -o $@ $^ -lrt
comsumer:comsumer.c
-$(CC) -o $@ $^ -lrt
打开两个终端实现信息通讯




五、信号




信号处理例程

cpp
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
void signal_handler(int signalnum)
{
printf("\n接收到信号%d,停止程序\n",signalnum);
exit(EXIT_SUCCESS);
}
int main(int argc, char const *argv[])
{
if(signal(SIGINT,signal_handler) == SIG_ERR)
{
perror("signal");
return 1;
}
while(1)
{
sleep(1);
printf("你好,在吗?\n");
}
return 0;
}
makefile
cpp
signal_test:signal_test.c
-$(CC) -o $@ $^
-./$@
-rm ./$@
