【linux应用软件编程】进程间的通信方式1【管道&IPC】

文章目录

  • 进程间的通信方式
    • 一、进程间的三种通信方式
    • 二、古老的通信方式
      • [2.1 无名管道](#2.1 无名管道)
      • [2.2 有名管道](#2.2 有名管道)
      • [2.3 信号](#2.3 信号)
        • [2.3.1 信号的定义及常见信号](#2.3.1 信号的定义及常见信号)
        • [2.3.2 注册信号](#2.3.2 注册信号)
        • [2.3.3 发生信号](#2.3.3 发生信号)
    • 三、IPC对象通信
      • [3.1 消息队列](#3.1 消息队列)
        • [3.1.1 ftok](#3.1.1 ftok)
        • [3.1.2 msgget](#3.1.2 msgget)
        • [3.1.3 msgsnd/msgrcv](#3.1.3 msgsnd/msgrcv)
        • [3.1.4 msgctl](#3.1.4 msgctl)
      • [3.2 共享内存](#3.2 共享内存)
        • [3.2.1 shmget](#3.2.1 shmget)
        • [3.2.2 shmat](#3.2.2 shmat)
        • [3.2.3 shmctl](#3.2.3 shmctl)

进程间的通信方式

一、进程间的三种通信方式

IPC 进程间通信 interprocess communicate

三大类:

  • 同一主机进程间通信

    1、古老的通信方式

    无名管道

    有名管道

    信号

    2、IPC对象通信 system v

    共享内存

    消息队列

    信号量集

  • 主要用在不同主机进程间通信

    3、socket通信

    网络通信

二、古老的通信方式

无名管道:只能用在具有亲缘关系的进程间通信(父子进程)。

有名管道:可以用在同一主机,任意进程间通信。

2.1 无名管道

只能用在具有亲缘关系的进程间通信(父子进程)。

操作流程:

  1. 创建并打开管道:pipe()

  2. 读管道:read();

  3. 写管道:write();

  4. 关闭管道:close();

  • pipe

    • 函数原型:
    c 复制代码
    int pipe(int pipefd[2]);
    • 功能:

    创建并打开一个无名管道

    • 参数:

    pipefd:管道读端和写端的文件描述符

    pipefd[0] 读端

    pipefd[1] 写端

    • 返回值:

    成功:0

    失败:-1

管道的特点:

管道本质是内核中的一段缓冲区,默认64K字节,遵循队列存储方式。(FIFO)

  1. 写阻塞:当管道的读写端都存在时,管道写满数据时,发生写堵塞;
  2. 读阻塞:当管道的读写端都存在时,管道为空时,读管道发生读阻塞。
  3. 读返回0:当管道没有写端,只有读端时,管道中有数据则读出数据;无数据时,不再出现读阻塞,直接返回0。
  4. 管道破裂:当所有进程都关闭了管道读端,管道没有读端向管道中写数据时,会发生管道破裂数据。

2.2 有名管道

可以用在同一主机,任意进程间通信。

  1. 创建有名管道文件: mkfifo ();
  2. 打开管道文件: open ();
  3. 写管道文件:write ();
  4. 读管道文件:read ();
  5. 关闭管道文件:close ();

2.3 信号

2.3.1 信号的定义及常见信号

信号:通知(不携带数据)

信号:软中断

(1) SIGHUP (2) SIGINT (3) SIGQUIT (4) SIGILL (5) SIGTRAP (6) SIGABRT (7) SIGBUS (8) SIGFPE (9) SIGKILL (10) SIGUSR1 (11) SIGSEGV (12) SIGUSR2 (13) SIGPIPE (14) SIGALRM (15) SIGTERM (16) SIGSTKFLT (17) SIGCHLD (18) SIGCONT (19) SIGSTOP (20) SIGTSTP (21) SIGTTIN (22) SIGTTOU (23) SIGURG (24) SIGXCPU (25) SIGXFSZ (26) SIGVTALRM (27) SIGPROF (28) SIGWINCH (29) SIGIO (30) SIGPWR (31) SIGSYS (34) SIGRTMIN (35) SIGRTMIN+1 (36) SIGRTMIN+2 (37) SIGRTMIN+3 (38) SIGRTMIN+4 (39) SIGRTMIN+5 (40) SIGRTMIN+6 (41) SIGRTMIN+7 (42) SIGRTMIN+8 (43) SIGRTMIN+9 (44) SIGRTMIN+10 (45) SIGRTMIN+11 (46) SIGRTMIN+12 (47) SIGRTMIN+13 (48) SIGRTMIN+14 (49) SIGRTMIN+15 (50) SIGRTMAX-14 (51) SIGRTMAX-13 (52) SIGRTMAX-12 (53) SIGRTMAX-11 (54) SIGRTMAX-10 (55) SIGRTMAX-9 (56) SIGRTMAX-8 (57) SIGRTMAX-7 (58) SIGRTMAX-6 (59) SIGRTMAX-5 (60) SIGRTMAX-4 (61) SIGRTMAX-3 (62) SIGRTMAX-2 (63) SIGRTMAX-1 (64) SIGRTMAX

  • 常用信号:

    2) SIGINT:ctrl + c

    让一个进程被打断

    3) SIGQUIT:ctrl +

    让一个进程结束

    9) SIGKILL:

    强制让一个进程结束

    11)SIGSEGV:

    让一个进程结束(段错误)

    13)SIGPIPE:

    让一个进程结束(管道破裂)

    14)SIGALRM:

    让一个进程结束(定时时间到达)

    17)SIGCHLD:

    子进程结束时发送给父进程

    18)SIGCONT:

    让停止态的进程继续执行

    19)SIGSTOP:

    让运行态的进程进入停止态(暂停)强制停止

    20)SIGTSTP:

    ctrl + z 让进程进入暂停态,后台进程

    来自终端的停止信号

    10 SIGUSR1

    12 SIGUSR2

    专门预留给程序员使用的未定义信号。

2.3.2 注册信号

信号处理方式:

  1. 忽略 :不处理
  2. 缺省 :按照操作系统默认方式处理
  3. 捕获 :按照自定义方式处理
  • 函数原型:

    c 复制代码
    sighandler_t signal(int signum, sighandler_t handler);
  • 功能:

    注册一个信号

  • 参数:

    signum :要注册的信号的编号

    handler:对信号的处理方式

    1. SIG_IGN :按忽略方式处理
    2. SIG_DFL:按照缺省方式处理
    3. 自定义的函数:按照捕获方式处理
  • 返回值:

    成功:handler

    失败:SIG_ERR

注意

  1. 如果信号不注册,自动按照默认方式(缺省)处理;大多数信号默认处理方式是结束一个进程;

  2. 信号能早注册就尽量早注册。

2.3.3 发生信号
kill
  • 函数原型:

    c 复制代码
    #include <sys/types.h>
    #include <signal.h>
    int kill(pid_t pid, int sig);
  • 功能: 发送一个信号给指定进程。

  • 参数: pid:接收信号的进程;

    sig:信号的编号。

  • 返回值: 成功:返回0;

    失败:返回-1.

异步回收

pause
  • 函数原型:

    c 复制代码
    #include <unistd.h>
    int pause(void);
  • 功能: 暂停/挂起一个进程 。

  • 返回值: 成功:返回

    失败:返回

alarm
  • 函数原型:

    c 复制代码
    #include <unistd.h>
    unsigned int alarm(unsigned int seconds);
  • 功能:定时若干秒后发送一个SIGALRM的信号。

三、IPC对象通信

3.1 消息队列

将进程间通信的数据封装成消息体发送;

增加消息类型,可以根据消息的类型设置数据的优先级。

  1. 获取IPC的key值:ftok();
  2. 创建消息队列:msgget();
  3. 发送消息队列消息:msgsnd();
  4. 接收消息队列消息:msgrcv();
  5. 删除消息队列:msgctl();
3.1.1 ftok
  • 函数原型:
c 复制代码
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
  • 功能: 获取IPC的key值。
  • 参数: pathname:路径名(任意路径,但读写端需一致);

    proj_id:任意符号或数字,需要独一无二。

  • 返回值: 成功:key_t :获取到的IPC的key值;

    失败:返回-1。

3.1.2 msgget
  • 函数原型:

    c 复制代码
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    int msgget(key_t key, int msgflg);
  • 功能: 根据key值创建一个消息队列。

  • 参数: key:IPC的key值;

    msgflg:IPC_CREAT(需要在后面加上mode/读写权限,如:IPC_CREAT|0664);IPC_EXCL

  • 返回值: 成功:消息队列的ID;

    失败:-1.

3.1.3 msgsnd/msgrcv
  • 函数原型:

    c 复制代码
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    
    int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
    ssize_t msgrcv(int msqid, void *msgp,size_t msgsz, long msgtyp,int msgflg);
  • 功能:

    发送和接收消息。

  • 参数:

    msqid:消息队列的ID;

    msgp:消息体

    struct msgbuf {

    long mtype; /* message type, must be > 0 /
    char mtext1; /
    message data */

    };

    msgsz:消息的正文大小;

    msgflg:标志位;一般以0默认方式(接收以阻塞方式)。

    msgtyp:消息类型。

  • 返回值:

    成功:发送返回0;接收返回接收数据的大小;

    失败:均返回-1。

3.1.4 msgctl
  • 函数原型:
c 复制代码
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
  • 功能: 操作IPC对象对应的消息队列。
  • 参数: msqid:消息队列的id;

    cmd:操作方法:

    1. IPC_STAT:

    2. IPC_SET:设置;

    3. IPC_RMID:删除操作。

    buf:

    IPC_RMID:buff------>NULL

  • 返回值: 成功:0;

    失败:-1;

注意

linux终端指令:

ipcs -a 查看消息队列。

ipcrm -q msgid 通过消息队列id删除消息队列

ipcrm -Q msgkey 通过消息队列key值删除消息队列

与管道的区别:

  1. 将进程间通信的数据封装成消息体发送;
  2. 增加消息类型,可以根据消息的消息类型设置数据的优先级

3.2 共享内存

共享内存:进程间效率最高的通信方式。

利用内存映射技术,避免了数据的反复拷贝。

实现方法:

  1. 获取一个IPC对象key值;ftok();

  2. 创建共享内存;shmget();

  3. 共享内存和用户进程空间建立内存映射关系;shmat();

  4. 向用户空间写入/读出数据;指针直接访问即可

  5. 解除映射关系;shmdt();

  6. 删除共享内存。shmctl();

3.2.1 shmget
  • 函数原型:

    c 复制代码
    #include <sys/ipc.h>
    #include <sys/shm.h>
    
    int shmget(key_t key, size_t size, int shmflg);
  • 功能: 创建一块共享内存。

  • 参数: key:IPC对象key值。

    size:共享内存的大小(PAGE_SIZE,4096字节);

    shmflg:IPC_CREAT | 0664。

  • 返回值: 成功:id

    失败:-1.

3.2.2 shmat
  • 函数原型:

    c 复制代码
    #include <sys/types.h>
    #include <sys/shm.h>
    
    void *shmat(int shmid, const void *shmaddr, int shmflg);
  • 功能:

  • 参数: shmid:共享内存id;

    shmaddr:映射的用户内存空间首地址

    1. NULL:由操作系统选择用户空间并返回首地址;

    shmflg:

    1. SHM_RDONLY:只读
    2. !SHM_RDONLY:读写
  • 返回值: 成功:返回共享内存起始虚拟地址 void*,进程通过这个指针读写共享内存;

    失败:返回 (void *)-1,设置 errno。

3.2.3 shmctl
  • 函数原型:

    c 复制代码
    #include <sys/ipc.h>
    #include <sys/shm.h>
    
    int shmctl(int shmid, int cmd, struct shmid_ds *buf);
  • 功能:

    操作共享内存。

  • 参数:

    shmid:共享存储id;

    cmd:操作指令(IPC_RMID删除)

    buf:NULL

  • 返回值:

    成功:0;

    失败:-1。

相关推荐
AlfredZhao3 小时前
用 crontab 给 LLM 使用量装上“监控眼”
linux
刃神太酷啦6 小时前
Linux 系统 MySQL 完整安装配置教程:从卸载 MariaDB 到优化 my.cnf----《Hello MySQL!》(1)
android·linux·c语言·c++·mysql·leetcode·mariadb
赵文宇(温玉)6 小时前
OpenEuler24.03 SP4 系统安装(欧拉/麒麟V10)
linux·openeuler·欧拉
Brilliantwxx8 小时前
【Linux】 进程(7)深度剖析 进程内核O(1)调度队列 + 饥饿问题
linux·运维·服务器
刚入门的大一新生9 小时前
Linux-命令行参数和环境变量
linux·运维·服务器
我星期八休息10 小时前
Linux I/O多路转接—epoll
java·linux·运维·服务器·开发语言·jvm·算法
wuminyu10 小时前
Java FFM处理网络读写事件源码剖析
java·linux·c语言·jvm·c++
实心儿儿10 小时前
Linux —— 数据链路层
linux·网络·智能路由器
智购科技无人售货机厂家11 小时前
2026自动售货机出货口防夹手设计:从红外检测到电机反转的工程实践~YH
大数据·linux·单片机·嵌入式硬件·微信