linux进程通信编程,Linux编程(进程的五种通信)

引言:IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等。其中 Socket和Streams支持不同主机上的两个进程IPC。

一、管道

概念:管道分为无名管道和命名管道。管道是一种半双工的通信方式(半双工即信息既可由A传到B,又能由B传A,但只能由一个方向上的传输存在),数据只能单向流动。管道的问题在于他们没有名字,只能在具有亲缘关系(父子进程间)的进程间使用。

管道特点:

①半双工的通信方式。

②只能用于具有亲缘关系的进程间的通信。

③管道不储存数据,只存在于内存。

1、无名管道

函数原型:

#include

int pipe(int fd[2]);

返回值为整形,若成功则范围0,失败则返回1.

其中fd[0]为只读打开,fd[1]为只写打开.

2、命名管道

#include

#include

int mkfifo(const char *pathname, mode_t mode);

返回值为整形,若成功则范围0,失败则返回1.

参数const char *pathname:路径名

mode_t mode:一般使用0600(可读可写)

注意:命名管道一般与open、read、write合用进行传送消息.

二、消息队列

消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。

特点:

①消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。

②消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。

③消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。

#include

1.创建或打开消息队列:成功返回队列ID,失败返回-1

int msgget(key_t key, int flag);

key相当于为索引(可用ftok函数获取key值),通过key在linux找到相应的队列。

2.添加消息:成功返回0,失败返回-1

int msgsnd(int msqid, const void *ptr, size_t size, int flag);

3.读取消息:成功返回消息数据的长度,失败返回-1

int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);

4.控制消息队列(队列移除):成功返回0,失败返回-1

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

eg:msgctl(msgID,IPC_RMID,NULL);

三、共享内存

共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区

特点:

①共享内存是最快的一种 IPC,因为进程是直接对内存进行存取。

②多个进程可以同时操作,需要进行同步。

③信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。

#include

1. 创建或获取一个共享内存:成功返回共享内存ID,失败返回-1

int shmget(key_t key, size_t size, int flag);

2 连接共享内存到当前进程的地址空间:成功返回指向共享内存的指针,失败返回-1

void *shmat(int shm_id, const void *addr, int flag);

eg:shamat(shmID,0,0) //让内核自动安排共享内存,并具备可读可写.

3 断开与共享内存的连接:成功返回0,失败返回-1

int shmdt(void *addr);

4 控制共享内存的相关信息:成功返回0,失败返回-1

int shmctl(int shm_id, int cmd, struct shmid_ds *buf);

eg:shmctl(shmID,IPC_RMID,NULL);

实现共享内存编程思路:

①创建共享内存 shmget()

②映射 shmat()

③进行数据交换(可直接对地址进行赋值strcpy)。

④释放共享内存 shmdt()

⑤关闭 shmctl()

四、信号

1、信号的处理:

信号的处理有三种方法,分别是:忽略、捕捉和默认动作

忽略信号,大多数信号可以使用这个方式来处理,但是有两种信号不能被忽略(分别是 SIGKILL和SIGSTOP)。因为他们向内核和超级用户提供了进程终止和停止的可靠方法,如果忽略了,那么这个进程就变成了没人能管理的的进程,显然是内核设计者不希望看到的场景

捕捉信号,需要告诉内核,用户希望如何处理某一种信号,说白了就是写一个信号处理函数,然后将这个函数告诉内核。当该信号产生时,由内核来调用用户自定义的函数,以此来实现某种信号的处理。

系统默认动作,对于每个信号来说,系统都对应由默认的处理动作,当发生了该信号,系统会自动执行。不过,对系统来说,大部分的处理方式都比较粗暴,就是直接杀死该进程。

具体的信号默认动作可以使用man 7 signal来查看系统的具体定义。在此,我就不详细展开了,需要查看的,可以自行查看。

2、信号的使用:

kill -信号编号 进程id号

3、信号处理函数

①入门版signal

发送指令kill

int kill(pid_t pid, int sig);

绑定信号signal

sighandler_t signal(int signum, sighandler_t handler);

#include

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

第一个参数为:捕捉的信号

第二个参数为:信号处理函数

void handler(int signum){

}

忽略信号(依然可以杀死)

eg:signal(SIGINT,SIG_IGN);

②高级版signaction()接收信号

#include

int sigaction (int signum, const struct sigaction *act,structsigaction*oldact);

第一个参数为:捕捉的信号

第二个参数为:绑定某些功能参数的结构体

第三个参数:备份

struct sigaction {

void (*sa_handler)(int); //信号处理程序,不接手额外数据

void (*sa_sigaction)(int, siginfo_t *, void *); //信号处理程序,接收额外数据

sigset_t sa_mask;

int sa_flags;

void (*sa_restorer)(void);

};

第一个参数为:函数指针1

第二个参数为:函数指针2

第三个参数为:结构体

第四个参数为:标记

如何发送信号?

#include

int sigqueue(pid_t pid, int sig, const union sigval value);

第一个参数为:发给谁

第二个参数为:什么信号

第三个参数为:发送的消息(int或char)

五、信号量

1、信号量(semaphore)与已经介绍过的 IPC 结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。

特点:

①信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。

②信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。

③每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数。

④支持信号量组

#include

1.创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1

int semget(key_t key, int num_sems, int sem_flags);

第二个参数为:信号量集的个数

2.对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1

int semop(int semid, struct sembuf semoparray[], size_t numops);

3.控制信号量的相关信息

int semctl(int semid, int sem_num, int cmd, ...);

第二个参数为:操作第几个信号量

第四个参数需定义一个联合体.

union semun {

int val; /* Value for SETVAL */

struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */

unsigned short *array; /* Array for GETALL, SETALL */

struct seminfo *__buf; /* Buffer for IPC_INFO

(Linux-specific) */

};

2、PV操作

int semop(int semid, struct sembuf *sops, unsigned nsops);

第二个参数为:配置信号量个数

第三个参数为:指针,指向第二个信号量的地址。

```c

key_t key;

key=ftok(".",1);

//int semget(key_t key, int nsems, int semflg);

int semid=semget(key,1,IPC_CREAT|0666); //获取信号量

union semun initsem;

initsem.val=0; //操作第0个信号的值

//int semctl(int semid, int semnum, int cmd, ...);

semctl(semid,0,SETVAL,initsem);//SETVAL设置信号量的值

取钥匙

```c

void pGetKey(int id)

{

struct sembuf set;

set.sem_num=0;

set.sem_op=-1;

set.sem_flg=SEM_UNDO;

semop(id,&set,1);

printf("getkey\n");

}

放钥匙

void vPutBackKey(int id)

{

struct sembuf set;

set.sem_num=0;

set.sem_op=1;

set.sem_flg=SEM_UNDO;

semop(id,&set,1);

printf("put back the key\n");

}

标签:信号,int,void,编程,信号量,五种,key,Linux,共享内存

来源: https://blog.csdn.net/PPPPPPPKD/article/details/115655359

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值