进程间通信 IPC

进程间通信 IPC

1.无名管道
2.有名管道
3.信号
4.共享内存
5.消息队列
6.信号量
7.SOCKET

一.无名管道

创建无名管道:

		   int pipe(int pipefd[2]);
		   参数  pipefd 读写端
		   返回值  成功与否  0:成功

搜索
注:fd[0]表示read端,fd[1]表示写端;
在这里插入图片描述
注:子进程继承父进程的fd,读端和写端
在这里插入图片描述
注:这是父进程
在这里插入图片描述
注:这是子进程
父进程向子进程发送消息,关闭父进程read端和子进程write端,这样有两个好处,使用fd时不会出错保证半双工通信。

二.有名管道

创建有名管道

	      int mkfifo(const char *pathname, mode_t mode);
          参数:pathname  文件名
                mode  文件权限
          返回值:成功返回0

在这里插入图片描述
在这里插入图片描述
先创建一个有名管道,p为管道文件
在这里插入图片描述
先从一端写入管道
在这里插入图片描述
再从管道中读取
注:read端和write端必须同时开启,否则不能执行任意一个。

三.信号:由一个进程向另一个进程发送中断消息,可通过kill –l查看,共64个信号。

    1)unsigned int alarm(unsigned int seconds);    自己给自己发信号
     参数 : 定时器倒计时时间,精度:秒
     返回值:1 之前有定时器计时,返回剩余秒数,否则返回0,出错返回-1

在这里插入图片描述

	2)int kill(pid_t pid, int sig);
     参数:pid 目标进程ID号
           sig  信号的值

在这里插入图片描述
注:这个kill为系统调用,与命令kill用法相似

	3)信号注册函数
     typedef void (*sighandler_t)(int);
     sighandler_t signal(int signum, sighandler_t handler);
     参数:signum 指定接受信号的种类
           handler 相关的信号处理函数

在这里插入图片描述
定义新的数据类型:
在这里插入图片描述
信号函数 :
在这里插入图片描述
注:如果碰到14号信号,则用handle函数处理。

四.本次套接字:Socket

本地地址结构(bind时用):
	<sys/un.h>
	struct sockaddr_un       
 	{
		sa_family_t  sun_family;	     //AF_UNIX
    	char  sun_path[108];         // 套接字文件的路径
	};
	
1 tcp方式
	1 设置socket套接口协议为PF_UNIX
	2 服务端注意绑定地址不是sockaddr_in,而是sockaddr_un
	3 客户端需要connect时设置的结构体是sockaddr_un,对应文件地址应与服务端设置一致
2 udp方式
	1 设置socket套接口协议为PF_UNIX
	2 服务端注意绑定地址不是sockaddr_in,而是sockaddr_un
	3 如果需要交互的话,客户端也需要bind一个客户端的套接口文件,不能与服务端的socket文件同名
	
本地套接字udp互相通信,为什么客户端需要绑定一个与服务端不相同的socket文件?
	在发送数据过程中,客户端知道服务端绑定的socket文件,所以,客户端能够发送数据给服务端。
	但是如果客户端没有绑定socket文件,相当与只发送数据,但服务端不知道谁发过来的。
	所以,互相通信时,客户端需要绑定一个socket文件,以便服务端向客户端发送数据。
系统IPC

一.共享内存

1.创建共享内存:int shmget(key_t key, size_t size, int shmflg);
    参数: key 键值:通信双方约定的共享内存的代号
         size 共享内存片段大小:以字节为单位
         shmflg 标志位:类比于open
		返回值:共享内存的id

在这里插入图片描述
注: ICP_CREAT表示创建一个共享内存,0666为其权限。

2 将共享内存映射进当前进程中:void *shmat(int shmid, const void *shmaddr, int shmflg);
   参数  shmid:共享内存的id
         shmaddr:要被映射的真实的物理地址  一般设置为NULL
         shmflg 标志位   0使用默认标志
    返回值:映射之后的私有地址

3 释放映射进来的地址:int shmdt(const void *shmaddr);

二.信号量:与sem_init创建的信号量类似;本质为个计数器

 1.创建: int semget(key_t key, int nsems, int semflg);
     返回值:信号量集id      失败  -1
     参数:key 键值:IPC_PRIVATE   
	       nsems:信号量集中信号量个数
	       Semflg:IPC_CREAT

三.消息队列

1.创建:int msgget(key_t key, int msgflg);
返回值:消息队列id       失败   -1
参数:key:键值      msgflg:标志位   0使用默认标志

在这里插入图片描述
2.获取和设置消息队列属性

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
有点复杂!!!

3.新消息加入队尾

int  msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
返回值:成功 0   失败 -1
参数:msgp:消息类型和内容,可为任意类型结构体,但第一字节必为long类型且必大于0;
  Msgsz:消息大小,字节
Msgflg:标志位,IPC_NOWAIT:当消息队列满时,立即返回错误;

4.从消息队列读取消息

	ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
  说明:从msqid消息队列中读取消息并存于msgp中,并删除此消息;
返回值:成功:读到的数据长度  失败   -1
参数:msgp:存放消息的结构体,类型要与msgsnd函数发送的结构体一致
Msgsz:要接受消息的大小
Msgtyp:0  接收第一个消息
    >0 接收类型等于Msgtyp的第一个消息
	<0 接收类型小于等于Msgtyp绝对值的第		一个消息
	Msgflg: 0  阻塞接收消息

几种进程间通信方式比较

从同步、数据传输、传输方式、进程数量的角度分析
1.无名管道:同步,只能用于亲缘进程通信,半双工,通讯时读写时机较难控制,且不适合大量进程相互通信;

2.有名管道:同步,用于非亲缘进程通信,半双工,大量进程互相通信时,创建的管道文件较多,不易维护,所以不适合大量进程互相通信;

3.信号:异步通信,不能携带数据,只起到通知作用;

4.共享内存:同步,不宜过大,因为在内核中分配内存,相当于多进程的全局变量,访问共享内存时需要控制访问顺序(同步互斥);也不适用于多进程通信;

5.消息队列:数据量不宜过大,因为在内核中分配内存,指定读取数据进程比较复杂且不宜大量进程间通信;

6.信号量,同步和互斥作用不能携带数据;

7.本地进程间通信socket:
专门用于本地通信的套接字,网络套接字绑定时是IP和端口,本地套接字是套接字文件;本地有点像网络套接字和管道的结合,跟其他进程间通信比较效率更高、因为只是在应用层之间,不经过协议栈,不用打包拆包;
可以进行多进程间互相通信,使用IO多路复用方式,服务端对通信描述符处理为串行处理,所以不需要进程同步互斥控制,支持tcp和udp方式;
tcp方式,服务端与客户端只需要一个套接字文件进行数据交换,比较容易实现,代码简单,如果使用udp方式,客户端与服务端需要单独绑定各自的套接字文件,当多个客户端时,套接字文件较多,所以,本地套接字通信使用tcp;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值