linux进程间通信(进程控制)

本文详细介绍了Linux系统中进程间通信的各种方式,包括管道通信、信号通信、IPC通信、Socket通信等,阐述了它们的工作原理、适用场景及具体实现方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用户空间进程间是不可能通信的(因为两个进程间是独立的两个空间),通过linux内核(内核空间对象)来进行通信。

线程:

一个进程中的不同线程间可以通信,可以在用户空间通信,通过全局变量通信。

哪几种通信方式?(内核对象来划分的)

管道通信:无名管道、有名管道(文件系统中有名)

信号通信:信号(通知)通信包括:信号的发送、信号的接收和信号的处理。

IPC(Inter-Process Communication)通信:共享内存、消息队列和信号灯

以上都是同一内核下的通信方式

Socdet通信:存在于一个网络中两个进程间的通信(两个Linux内核)。

思想:每一种通信方式都是基于文件IO的思想。

open:创建或打开进程通信对象,函数形式不一样,有的是有多个函数完成。

write:向进程通信对象中写入内容。函数形式可能不一样。

read:从进程通信对象中读取内容,函数形式可能不一样。

close:关闭或删除进程通信对象,形式可能不一样。 


各种内 核对象:

无名管道:在文件系统中无文件名称。

原理:管道其实是由队列来实现的。

由pipe函数创建管道,由系统调用。须包含头文件unistd.h

int pipe(int fd[2])

参数:有一个读端fd[0]和一个写端fd[1],这个规定不能变

成功返回0,失败返回-1.

注:

管道里面的东西,读完了就删除了。

如果管道中没有东西可读,就会读阻塞。也存在写阻塞,缓存大小5456

进程结束,管道就不存在了。

缺点:不能实现非父子进程间的通信。

有名管道:为了解决非父子进间的通信的问题。

注:linux七种文件类型

普通文件      -

目录文件     d

链接文件(特指软链接文件)     l

管道文件     p

int mkfifo(const char *filename,mode_t mode);//创建管道文件

参数:管道文件名,权限,仍然和unmask有关系。

成功返回0,失败-1.

有名只是文件系统中存一个文件节点,inode号

管道文件、套接字、字符设备、块设备只有inode号不占磁盘空间。普通文件和符号链接文件、目录文件不仅有inode号还占磁盘空间。

mkfifo只创建文件节点号,没有在内核中创建管道,只有通过open函数打开这个文件时才会在内核空间创建管道。


2019-11-28信号通信

信号在内核中已经存在的,在linux中使用kill -l可以查看内核所能发的信号。共64种。

信号的通信框架:

信号的发送(发送信号的进程)kill raise alarm

信号的接收(接收信号的进程):pause sleep while(1)

信号的处理(接收信号进程)signal

信号发送:头文件 #include <signal.h>   #include<sys/types.h>

原型:int keill(pid_t pid ,int sig)

注:

 pid     正数代表:要接收信号的进程号

             0信号被发送到所有和pid 进各一在同一个进各一组的进程

            -1信号发送到所有在进程表中的进程。

sig:    发送什么信号 (64种其中之 一)

正确返回0,出错-1。

 

raise发信号给自己  == kill(getpid(),sig)

所需要头文件 #include <signal.h>

#include <sys/types.h>

int raise(int sig);成功返回0出错-1.

 

alarm闹钟信号:也是一种只发给自己的函数,当前的进程

1、只会发送SIGALARM信号,收到信号后终止当前的进程。

2、会让内核定时一段时间后发送信号,raise会立即执行。

所需要头文件  #include <nuistd.h>

unsigned int alarm(unsigned int seconds)

参数:指定秒数

成功:如果调用此alarm()前,进程中已经设置了闹钟时间,则返回上一个闹钟的剩余时间,否则返回0

出错-1.

 

信号的接收:接收信号进程的条件:想接收,就不要结束

pause:进程状态为S也就是sleep状态

头文件:#include <unistd.h>

int pause(void)

成功0,出错-1


2019-12-03

信号处理:自己处理信号的方法告诉内核,这样你的进程收到这个信号后就会采用你自己的处理方式。

所需要头文件#include <signal.h>

void (*signal(int signum,void(*handler)(int)))(int)

signalnum:指定信号

handler: SIG_IGN:忽略该信号

SIG_DFL:采用系统默认方式处理信号

自定义的信号处理函数指针

成功:设置之前的信号处理方式,出错-1.

signal第一个参数是告诉内核处理哪个信号

第二个参数,怎么处理这个信号。返回值是一个函数指针。


2019年12月10日

IPC通信,不同于以上的通信方式。

使用的基本流程
通过get系统调用创建或打开一个IPC对象
给定一个整数key,get调用会返回一个整数标识,即IPC标识符

通过这个标识符来引用IPC对象并进行各种操作

通过ctl系统调用获或设置IPC对象的属性、或者删除一个对象

IPC对象具有的权限定义在ipc.h头文件中

下表为system V 各个IPC对象之间的差异

接口消息队列信号量 共享内存
头文件<sys/msg.h><sys/sem.h><sys/shm.h>
关联数据结构msqid_dssemid_ds shmid_ds
创建/打开对象msgget()  semget() shmget()+shmat()
关闭对象(无)(无)shmdt()
控制操作 msgctl() semctl()shmctl()
执行IPC msgsnd()—写入消息semop()—测试/调整信号量 访问共享区中的内存

还是要以文件IO的思想来学习。

1、创建或打开共享内存(注:共享内存什么样???类似于创建一个数组或用malloc申请的空间)

所需要的头文件:#include <sys/types.h>

                                   #include <sys/ipc.h>

                                  #include <sys/shm.h>

函数原型:int shmget(key_t key,int size,int shmflg)

key值:IPC_PRIVATE或ftok的返回值

size:共享内存区大小

shmflg:同open函数的权限位,也可以用8进制表示法。

返回值:共享内存段标识符-ID-文件描述符。出错-1.

 

查看IPC对象:ipcs -m

删除IPC对象 :ipcrm -m + id

返回值:共享内存段标识符  IPC的ID号。

 

ftok:创建key值

char ftok(const char *path,char key)

参数:第一个参数是文件路径和文件名

第二个参数:一个字符

正确返回一个key值,出错-1.

与IPC_PRIVATE不同,类似于有名与无名管道,IPC_PRIVATE可以实现有亲缘关系进程间通信。每次的key都是0.

用ftok创建的key可以实现无亲缘关系进程间通信。每次创建的key值都不一样。

 

共享内存读写操作:特点是使用地址映射的方式,到用户空间地址,这样很方便的进行读写操作。可以使用fgets,printf等用户读写函数操作共享内存。

void *shmat(int shmid,const void *shmaddr,int shmflg);

第一个参数:ID号,映射共享内存的哪一块。

第二个参数:映射到的地址,NULL为系统自动完成的映射。

第三个参数:shmflg:      SHM_RDONLY共享内存只读

                                             默认是0,表示共享内存可读写

成功:返回映射后的地址。失败:NULL。

 

shmdt:将进程(用户空间)里的地址映射删除

int shmdt(const void *shmaddr);

参数:shmaddr共享内存映射后的地址

成功:0失败-1.

共享内存的特点:

1、共享内存创建后,一直存在于内核中,直到被删除或系统关闭。

2、共享内存和管道不一样,读取后依然在内存中。

 

shmctl:删除共享内存对象(内核中的共享内存)

int shmctl(int shmid,int cmd,struct shmid_ds *buf)

shmid:要操作的共享内存标识符

cmd:IPC_STAT(获取对象属性)   --实现了ipc -m

           IPC_SET(设置对象属性)

           IPC_RMID(删除对象)    --实现了ipcrm -m命令

buf:指定IPC_STAT/IPC_SET时用以保存/设置属性

成功0出错-1.


2019-12-11消息队列

与管道队列的不同:是 一种链式队列,每个消息可以不同。而管道里的队列是一种顺序队列。

1、消息队列的创建或打开函数

所需要头文件:#include <sys/types.h>

                              #include <sys/pic.h>

                             #include <sys/msg.h>

int msgget(key_t key,int flag);

key:和消息队列关联的key值

flag:消息队列的访问权限

成功:消息队列的ID 出错:-1.

2、消息队列的删除

所需要头文件 #include <sys/types.h>

                            #include <sys/ipc.h>

                           #include <sys/msg.h>

int msgctl(int msgqid,int cmd,struct msqid_ds *buf);

msqid:消息队列的队列ID

cmd: IPC_STAT:读取消息队列的属性,并将其保存在buf指向的缓冲区中

IPC_SET:设置消息队列的属性,这个值取自buf 参数。

IPC_RMID:从系统中删除消息队列。

buf :消息队列的缓冲区

成功0出错-1.

3、消息队列的写入

所需要头文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

int msgsnd(int msgid,xonst void #msgp,size_t size,int flag);

msgid:消息队列的ID

msgp:指向消息的指针,学用的消息结构msgbuf如下:

struct msgbuf

{

long mthype;//消息类型

char mtext[N]; //消息正文

};

size:发送的消息正文的字节数

flag: IPC_NOWAIT   消息没有发送完成函数也会立即返回。

0:直到发送完成函数才返回。

成功0出错-1.

 

4、消息队列的读函数:msgrcv

所需要头文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

int msgrcv (int msgid, void *msgp; size_t size , long msgtype, int flag);

msgid:消息队列的ID

msgp:接收消息的缓冲区

size:要接收的消息的字节数

msgtype:0:接收消息队列中第一个消息。

大于0:接收消息队列中第一个类型为msgtyp的消息。

小于0:接收消息队列中类型值不大于msgtyp的绝对值且类型又最小的消息。

 

flag:0:若无消息函数会一直阻塞。

IPC_NOWAIT:若没有消息,进程会立即返回。

ENOMSG

成功:接收到消息的长度。

出错-1.

 

信号灯:

与posix信号量的区别

信号量指的是单个信号量,而信号灯是信号量的集合

所有针对信号灯的操作都是对一个集合的操作

所需要头文件

1、创建或打开一个信号灯

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

int semget(key_t key,int msems,int semflg);

key:和信号灯集关联的key值。

msems:信号灯集中包含的信号灯数目

semflg:信号灯集的访问权限

成功:信号灯集ID 出错-1。

2、删除一个信号灯:

所需要头文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

int semctl(int semid, int semnum, int cmd, ...union semnu ar(不是地址));

semid:信号民灯集ID

semnum:要修改的信号灯编号

cmd: GETVAL:获取信号灯的值

SETVAL:设置信号类的值

注:信号类的初始化,类似sem_init;

union semun

{

int val;//SETVAL:设置信号灯的值

struct semid_ds *buf;//IPC_STAT(获取对象属性)IPC_SET(设置对象属性)值

unsigned short *array;

struct seminfo *__buf;

}

IPC_RMID:从系统中删除信号灯集合

第四个参数可以有也可以没有

成功0出错-1.

3、信号灯的P操作

所需要头文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

int semop(int semid , struct sembuf *opsptr, size_t nops);

semid:信号灯集ID

struct sembuf

{

short sem_num;  //要操作的信号灯的编号

short sem_op;  // 0:等待,直到信号类的值变成0

                                 //1:释放资源,V操作

                                // -1消耗资源,P操作。

short sem_flg;//0,IPC_NOWAIT,SEM_UNDO

};

nops:要操作信号灯的个数。

成功0出错-1.

总结:只是过了一遍知识点,要想记住,需要在用的过程中随时翻翻,然后再补充自己的体会。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

guangod

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值