自学嵌入式 day30 IPC:进程间通信

IPC 进程间通信 :

一、类别:

1、古老的通信方式:无名管道 有名管道 信号

2、IPC对象通信: system v

消息队列(用的相对少,这里不讨论)

共享内存(在内核malloc一个空间)

信号量集

3、socket通信:网络通信

二、管道

1、特性:(1)、管道是 半双工的工作模式

(2)、所有的管道都是特殊的文件不支持定位操作。

(3)、管道是特殊文件,读写使用文件IO。

注:(1)单工:方向唯一

(2)半双工:左右错开收发

(3)全双工:任意时刻收发

2、无名管道:pipe ,只能给有亲缘关系进程通信

(1)特性: ①、读端存在,一直向管道中去写,超过64k(系统给的管道大小),写会阻塞(取走4k后取消阻塞)。

②、写端是存在的,读管道,如果管道为空的话,读会阻塞。

③、管道破裂,,读端关闭,写管道。

④、read 0 ,写端关闭,如果管道没有内容,read 0 ;

(2)使用步骤:创建管道 --》读写管道 --》关闭管道

(3)创建并打开管道: pipe函数

int pipe(int pipefd[2]);

功能:创建并打开一个无名管道

参数: pipefd[0] ==>无名管道的固定读端

pipefd[1] ==>无名管道的固定写端

返回值:成功 0

失败 -1;

①、写慢读快,会阻塞

#include<stdio.h>

#include<stdlib.h>

#include<unistd.h>

#include<string.h>

int main()

{

int fd[2] = {0};

int ret = pipe(fd);

if(-1 == ret)

{

perror("pipe\n");

return 1;

}

pid_t pid = fork();

if(pid > 0)

{

close(fd[0]);

sleep(3);

write(fd[1],"hello",5);

close(fd[1]);

}

else if(0 == ret)

{

close(fd[1]);

char buf[10] = {0};

read(fd[0],buf,sizeof(buf));

printf("father:%s\n",buf);

close(fd[0]);

}

else

{

perror("fork\n");

return 1;

}

return 0;

}

②、写快读慢,会阻塞

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <string.h>

int main()

{

int fd[2]={0};

int ret = pipe(fd);

if(ret == -1)

{

perror("pipe");

return 1;

}

pid_t pid = fork();

if(pid>0)

{

// fd[0] read fd[1] write

close(fd[0]); //close read end

char buf[1024]={0};

memset(buf,'a',sizeof(buf));

int i = 0 ;

for(i =0;i<65;i++)

{

write(fd[1],buf,1024);

printf("%d\n",i);

}

close(fd[1]);

}

else if (0 == pid)

{

close(fd[1]);

char buf[10]={0};

while(1)sleep(1);

close(fd[0]);

}

else

{

perror("fork");

return 1;

}

return 0;

}

③、管道破碎

include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <strings.h>

int main()

{

int fd[2]={0};

int ret = pipe(fd);

if(ret == -1)

{

perror("pipe");

return 1;

}

pid_t pid = fork();

if(pid>0)

{

// fd[0] read fd[1] write

close(fd[0]); //close read end

sleep(3);

write(fd[1],"hello",5); //触发管道破裂 gdb 观察

printf("aaaa\n");

close(fd[1]);

}

else if (0 == pid)

{

close(fd[1]);

close(fd[0]);

}

else

{

perror("fork");

return 1;

}

return 0;

}

注:set-fork-mode child:gdb调试中走子进程,在fork函数前使用

④、read 0

#include <stdio.h>

#include <stdlib.h>

#include <strings.h>

#include <unistd.h>

int main(int argc, char **argv)

{

int fd[2] = {0};

int ret = pipe(fd);

if (ret == -1)

{

perror("pipe");

return 1;

}

pid_t pid = fork();

if (pid > 0)

{

// fd[0] read fd[1] write

close(fd[0]); // close read end

write(fd[1], "hello", 5);

close(fd[1]);

exit(0);

}

else if (0 == pid)

{

close(fd[1]);

sleep(3);

while (1)

{

char buf[10] = {0};

int ret = read(fd[0], buf, sizeof(buf));

if(0 == ret) // read ==0 表示进程通信结束

{

printf("read 0\n");

break;

}

printf("father:%s\n", buf);

}

close(fd[0]);

}

else

{

perror("fork");

return 1;

}

return 0;

}

练习:复制文件:

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <strings.h>

#include <fcntl.h>

int main()

{

int fd[2]={0};

int ret = pipe(fd);

if(ret == -1)

{

perror("pipe");

return 1;

}

pid_t pid = fork();

if(pid>0)

{

// fd[0] read fd[1] write

close(fd[0]); //close read end

int srcfd = open("/home/linux/1.png",O_RDONLY);

if(-1 == srcfd)

{

perror("open");

exit(1);

}

while(1)

{

char buf[4096]={0};

int ret = read(srcfd,buf,sizeof(buf));//从图片里读

if(0 == ret)

{

break;

}

write(fd[1],buf,ret); //sizeof(buf) strlen(buf) //写到管道去

}

close(fd[1]);

close(srcfd);

}

else if (0 == pid)

{

close(fd[1]);

int dstfd = open("2.png",O_WRONLY|O_CREAT|O_TRUNC,0666);

if(-1 == dstfd)

{

perror(" child open");

return 1;

}

while(1)

{

char buf[4096]={0};

int ret = read(fd[0],buf,sizeof(buf));//从管道里读

if(0 == ret)

{

break;

}

write(dstfd,buf,ret);//写到图片里去

}

close(fd[0]);

close(dstfd);

}

else

{

perror("fork");

return 1;

}

return 0;

}

3、有名管道:fifo,有文件名称的管道

(1)使用步骤:创建有名管道 ==》打开有名管道 ==》读写管道

==》关闭管道 ==》卸载有名管道

(2)创建:int mkfifo(const char *pathname, mode_t mode);

功能:在指定的pathname路径+名称下创建一个权限为mode的有名管道文件。

参数:pathname要创建的有名管道路径+名称

mode 8进制文件权限。(默认0666)

返回值:成功 0

失败 -1;

(3)卸载管道:remove();

功能:将指定的pathname管道文件卸载,同时从文件系统中删除。

参数: ptahtname 要卸载的有名管道

返回值:成功 0

失败 -1;

①、write_fifo.c

#include <errno.h>

#include <fcntl.h>

#include <stdio.h>

#include <stdlib.h>

#include <strings.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <unistd.h>

int main()

{

int ret = mkfifo("fifo",0666);

if(-1 == ret)

{

if(EEXIST != errno)

{

perror("mkfifo");

return 1;

}

}

int fd = open("fifo",O_WRONLY);

if(-1 == fd)

{

perror("open");

return 1;

}

write(fd,"hello",5);

close(fd);

return 0;

}

②、read_fifo.c

#include <errno.h>

#include <fcntl.h>

#include <stdio.h>

#include <stdlib.h>

#include <strings.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <unistd.h>

int main()

{

int ret = mkfifo("fifo",0666);

if(-1 == ret)

{

if(EEXIST != errno)

{

perror("mkfifo");

return 1;

}

}

char buf[10] = {0};

int fd = open("fifo",O_RDONLY);

if(-1 == fd)

{

perror("open");

return 1;

}

read(fd,buf,sizeof(buf));

printf("r:%s\n",buf);

close(fd);

remove("fifo");

return 0;

}

注:(1)有名管道在执行open时会阻塞

(2)相同管道名不能二次创造,可用设置 if(EEXIST==erron)避免

(4)特性: (1)需要同步,位置在open函数

(2)可在父子进程中使用

(3)能手工操作有名管道实现数据传送

练习:用有名管道实现复制功能:

①、read_fifo.c

#include <errno.h>

#include <fcntl.h>

#include <stdio.h>

#include <stdlib.h>

#include <strings.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <unistd.h>

int main(int argc, char **argv)

{

int ret = mkfifo("fifo", 0666);

if (-1 == ret)

{

if (EEXIST != errno)

{

perror("mkfifo");

return 1;

}

}

int fd = open("fifo", O_RDONLY);

if (-1 == fd)

{

perror("open fifo");

return 1;

}

int dstfd = open("2.png",O_WRONLY|O_CREAT|O_TRUNC,0666);

if(-1 == dstfd)

{

perror("open 2.png");

return 1;

}

while(1)

{

char buf[4096]={0};

int ret = read(fd,buf,sizeof(buf));

if(0 == ret)

{

break;

}

write(dstfd,buf,ret);

}

close(fd);

close(dstfd);

remove("fifo");

// system("pause");

return 0;

}

②、write_fifo.c

#include <errno.h>

#include <fcntl.h>

#include <stdio.h>

#include <stdlib.h>

#include <strings.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <unistd.h>

int main(int argc, char **argv)

{

int ret = mkfifo("fifo", 0666);

if (-1 == ret)

{

if (EEXIST != errno)

{

perror("mkfifo");

return 1;

}

}

int fd = open("fifo", O_WRONLY);

if (-1 == fd)

{

perror("open fifo");

return 1;

}

int srcfd= open("/home/linux/1.png",O_RDONLY);

if(-1 == srcfd)

{

perror("open 1.png");

return 1;

}

while(1)

{

char buf[4096]={0};

int ret = read(srcfd,buf,sizeof(buf));

if(0 == ret)

{

break;

}

write(fd,buf,ret);

}

close(fd);

close(srcfd);

// system("pause");

return 0;

}

三、信号通信

1、应用:异步通信

2、如何响应:man 7 signal

term:结束进程

lgn:忽略信号

core:进程结束,保存关键点的信息

stop:暂停

cont:继续

3、信号:kill -l

4、发信号:

(1)kill:int kill(pid_t pid, int sig);

功能:通过该函数可以给pid进程发送信号为sig的系统信号。

参数:pid 要接收信号的进程pid

sig 当前程序要发送的信号编号

返回值:成功 0

失败 -1;

#include <sys/types.h>

#include <signal.h>

#include <errno.h>

#include <fcntl.h>

#include <stdio.h>

#include <stdlib.h>

#include <strings.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <unistd.h>

int main(int argc, char **argv)

{

if(argc<3)

{

printf("usage: ./a.out pid signum\n");

return 1;

}

pid_t pid = atoi(argv[1]);

int num = atoi(argv[2]);

int ret = kill(pid,num);

if(-1 == ret)

{

perror("kill");

return 1;

}

//system("pause");

return 0;

}

(2)unsigned int alarm(unsigned int seconds)

功能:定时由系统给当前进程发送信号,也称为闹钟函数

参数:second:秒数

#include <sys/types.h>

#include <signal.h>

#include <errno.h>

#include <fcntl.h>

#include <stdio.h>

#include <stdlib.h>

#include <strings.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <unistd.h>

int main()

{

alarm(5);

while(1)

{

printf("sleep...\n");

sleep(1);

}

return 0;

}

(3)int pause(void);

功能:进程暂停,不再继续执行,除非收到其他信号。

#include <sys/types.h>

#include <signal.h>

#include <errno.h>

#include <fcntl.h>

#include <stdio.h>

#include <stdlib.h>

#include <strings.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <unistd.h>

int main()

{

int i = 0;

while(1)

{

printf("work...\n");

i++;

sleep(1);

if(5 == i)

{

pause();

}

}

return 0;

}

(4)信号注册函数:typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

功能L:改变原有信号的功能

参数: signum:几号命令(不能改9,10号命令)

handler:函数名

①闹钟函数:

#include <sys/types.h>

#include <signal.h>

#include <errno.h>

#include <fcntl.h>

#include <stdio.h>

#include <stdlib.h>

#include <strings.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <unistd.h>

int flag = 0 ;

void handle(int num)

{

flag =1;

}

int main(int argc, char **argv)

{

signal(SIGALRM,handle);

alarm(5);

while(1)

{

if(0 == flag)

{

printf("sleep...\n");

}

else

{

printf("working...\n");

}

sleep(1);

}

system("pause");

return 0;

}

②、暂停函数的继续:

#include <errno.h>

#include <fcntl.h>

#include <signal.h>

#include <stdio.h>

#include <stdlib.h>

#include <strings.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <sys/types.h>

#include <unistd.h>

void handle(int num)

{

}

int main(int argc, char **argv)

{

signal(SIGCONT,handle);

int i = 0 ;

while(1)

{

printf("work... pid:%d\n",getpid());

sleep(1);

i++;

if(5 == i )

{

printf("暫停\n");

pause();

}

}

system("pause");

return 0;

}

③、用户自定义命令:

#include <errno.h>

#include <fcntl.h>

#include <signal.h>

#include <stdio.h>

#include <stdlib.h>

#include <strings.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <sys/types.h>

#include <unistd.h>

void handle1(int num)

{

static int i = 0;

printf("老爸叫你...\n");

i++;

if(i ==3)

{

signal(SIGUSR1,SIG_IGN); //忽略信号

}

}

void handle2(int num)

{

static int i = 0;

printf("老妈叫你...\n");

i++;

if(i ==3)

{

signal(SIGUSR2,SIG_DFL); //回复默认信号

}

}

int main(int argc, char **argv)

{

signal(SIGUSR1,handle1);

signal(SIGUSR2,handle2);

while(1)

{

printf("i'm playing pid:%d\n",getpid());

sleep(1);

}

system("pause");

return 0;

}

相关推荐
2401_873587821 小时前
Linux常见指令以及权限理解
linux·运维·服务器
RW~1 小时前
Minio安装配置,桶权限设置,nginx代理 https minio
运维·nginx·https·minio
Arthurmoo1 小时前
Linux系统之MySQL数据库基础
linux·数据库·mysql
李洋-蛟龙腾飞公司2 小时前
HarmonyOS NEXT应用元服务常见列表操作分组吸顶场景
linux·运维·windows
链上Sniper2 小时前
智能合约状态快照技术:实现 EVM 状态的快速同步与回滚
java·大数据·linux·运维·web3·区块链·智能合约
晨曦丿3 小时前
双11服务器
linux·服务器·网络
从零开始学习人工智能3 小时前
深入解析 OPC UA:工业自动化与物联网的关键技术
运维·物联网·自动化
wanhengidc3 小时前
UDP服务器主要是指什么意思?
服务器·网络协议·udp
李迟3 小时前
在Linux服务器上使用kvm创建虚拟机
java·linux·服务器
从后端到QT3 小时前
SRS流媒体服务器(8)源码分析之rtc/rtmp互相转码详解
运维·服务器·实时音视频