linux进程通信
e14: 进程间通信(进程之间发送/接收字符串/结构体):
传统的通信方式:
管道(有名管道 fifo,无名管道 pipe)
信号 signal
System V(基于IPC的对象): IPC对象: ipcrm [ -M key | -m id | -Q key | -q id | -S key | -s id ] ...
消息队列 message queue ipcs: ipcrm {shm|msg|sem} id...
共享内存 share memory -m shared memory segments
信号量集/信号灯集 semaphore -q message queues
-s semaphore arrays
-a all (this is the default)
----------------------------------------------------------------------------
| System V的流程: | system() - execute a shell command
| 已经存在的路径名---->ftok()---->key---->IPC对象---->id---->使用 | 调用/bin/sh -c command,执行命令command
| |
| key-----shmget(),msgget(),semget()----->IPC对象(id号) |
| eg:key=ftok("/",'a'); |
| id=msgget(key,IPC_CREAT|0666); |
| open(filename,O_CREAT,0666); |
----------------------------------------------------------------------------
BSD:
套接字 socket
e14-1: 无名管道pipe(用于具有亲缘关系的进程,单向的数据传输通道):
int pipe(int pipefd[2]);
pipefd[0]----读端,pipefd[1]----写端
----------------------------------------------------------------------
读端:
写端存在:
管道是有数据的,返回读取的字节数
管道是没有数据的,阻塞/等待直到管道中有数据
写端不存在:
管道是有数据的,返回读取的字节数
管道是没有数据的,返回0
写端:
读端存在:
管道有空间,返回写入的字节数
管道没有空间/空间不足,有多少写多少,直到写完返回
读端不存在:
进程被终止
e14-2: 有名管道fifo(first in first out)(用在独立的进程之间,双向的):
有名管道是独立于进程存在的
有名管道可以看成由文件名标识的一根管道
创建:mkfifo
删除:unlink
监听:open(O_RDONLY)
开始会话:open(O_WRONLY)
两个进程通过FIFO进行通信:发送----write
接收----read
结束通信:close
----------------------------------------------------------------------
关于阻塞:
读端:open(O_RDONLY);写端:open(O_WRONLY)
只有读端或者只有写端的时候,open调用会阻塞
验证方法:只运行read或者write程序
写端关闭:只剩下读端时,read立即返回0
读端关闭:只剩下写端时,写端会被终止
O_RDWR:两端都是O_RDWR方式打开时,两端都运行。如果一端退出,因为另一端以O_RDWR的方式打开,相当与自己也可以写,自己也可以读,在调用read,write时会阻塞
----------------------------------------------------------------------------------
多个进程读fifo:有名管道是一个队列,而不是常规文件。写端将字节写入队列,读端从队列的头部移出字节,每个读端都会将数据移出队列。所以如果想要保证读端都读到数据,写端必须要重写数据。
----------------------------------------------------------------------------------
竞态条件:FIFO不会出现竞态条件的问题。read和write系统调用是原子操作。读取操作将管道清空,而写入操作又将管道塞满。在读端和写端连通之前,系统内核会将进程挂起。
e14-3: 消息队列message queue:
key-----msgget()----->IPC对象(id号)
eg: 创建:key=ftok("/",'a');
id=msgget(key,IPC_CREAT|0666);
open(filename,O_CREAT,0666);
删除:msgctl:IPC_RMID
发送:msgsnd
接收:msgrcv
e14-4: 共享内存share memory:
最快速的进程间通信方式,适合大量数据的传输。他是一种高效率的进程间通信方式,进程可以直接读写内存空间,而不需要任何数据的copy
交互的时候不妨便,尤其是复杂的交互程序,需要同步/互斥
--------------------------------------------------------------------------------------------------------------------------------
共享内存的实现分为两个步骤:创建共享内存;映射共享内存,解除映射
创建/打开:shmget
删除:shmctl:IPC_RMID
内存映射:shmat:shmaddr--->内存映射指定的地址,若是NULL,表示由系统自动映射
shmflg---->默认是0,共享内存可读写,若是SHM_RDONLY,表示共享内存只读
内存解除映射:shmdt
e14-5: 信号量集/信号灯集semaphore:
信号量是一个内核变量,它可以被系统当中的任何进程所访问
进程之间可以使用这个变量来协调对于共享内存和其他资源的访问
信号量集是一个或多个信号量的一个集合,其中的每一个元素都是单独的信号量
信号量集机制------>解决进程间的同步与互斥
创建:semget
删除:semctl:IPC_RMID
初始化:semctl:SETVAL
修改:semop:sops---->结构体数组的首地址
nsops---->结构体数组的大小
结构体:struct sembuf{
unsigned short sem_num; /* semaphore number */
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
};
sem_op:
>0 对信号量的当前值进行增加
=0 等待直到信号量的值为0
<0 对信号量的当前值进行减少(如果不够减,就会等待)
sem_flag:SEM_UNDO,在进程终止前,对信号量进程恢复
e14-6: 信号signal:
信号来自内核
发送信号的方式:
1.键盘快捷键
2.内核在执行程序出错时。比如:非法段存取,浮点数溢出或除零运算
3.一个进程可以通过系统调用给另一个进程发送信号
特点:信号是一种异步通信方式,唯一的一种异步通信方式
信号可以直接进行用户空间过程和内核空间进程的交互
内核空间进程可以用信号来通知用户空间进程发生了哪些系统事件
------------------------------------------------------------------------------------------------------
用户空间进程对信号的响应方式:
1.忽略信号:对信号不做任何处理,其中,有两个信号不能忽略:SIGKILL(9) 和STGSTOP(10)
2.捕捉信号:定义信号处理函数,当信号发生时,执行相对应的信号处理函数
3.执行默认操作:linux对每种信号都规定了默认操作
--------------------------------------------------------------------------------------------------------
信号(kill -l):
1.SIGHUP(终止进程):
在用户终端连接结束的时候发出的,通常是终端的控制进程结束时,通知同一会话的各个进程组与控制终端不再连接
2.SIGINT(终止进程):
用户输入“ctrl + c”时发出,前台进程中的每一个进程会接收到这个信号
3.SIGQUIT(终止进程):
用户输入“ctrl + \”时发出
9.SIGKILL(终止进程):
立即结束程序的运行,不能被忽略
14.SIGALRM(终止进程):
当一个定时器到时的时候发送
===============================================================================================
| sleep:添加延时 |
| sleep(n)----将当前进程挂起n秒 |
| 1.为SIGALRM设置处理函数 |
| 2.调用alarm(num_seconds):设置一个定时器,在num_seconds秒之后发送SIGALRM信号 |
| alarm也叫做闹钟函数,如果之前有设置定时器,前面设置的会失效 |
| 3.pause():挂起进程直到信号到达,任何的信号都可以唤醒进程 |
===============================================================================================
| usleep:实现精度更高的延时 |
| int usleep(useconds_t usec); |
| |
| 获取或设置间隔计时器: |
| int getitimer(int which, struct itimerval *curr_value); |
| int setitimer(int which, const struct itimerval *new_value,struct itimerval *old_value); |
| |
| which:获取或设置的计时器 |
| ITIMER_REAL:真实----------发送 SIGALRM |
| ITIMER_VIRTUAL:虚拟-------------发送 SIGVTALRM |
| ITIMER_PROF:实用----------发送 SIGPROF |
| struct itimerval 结构体 |
| struct itimerval { |
| struct timeval it_interval; /* next value */ |
| struct timeval it_value; /* current value */ |
| }; |
| struct timeval { |
| long tv_sec; /* seconds */ |
| long tv_usec; /* microseconds */ |
| }; |
| |
| tv_sec tv_usec |
| ---------------------------------------------- |
| it_valuse | | (初始时间) |
| it_interval | | (间隔时间) |
===============================================================================================
17.SIGCHLD(忽略):
子进程改变状态的时候,父进程会收到这个信号
19.SIGSTOP(暂停进程,不消灭进程):
用于暂停一个进程,且不能被忽略,不能定义处理函数
20.SIGTSTP(暂停进程,不消灭进程):
用于暂停交互进程,用户输入“ctrl + z”发出信号
----------------------------------------------------------------------------------------------------------------
信号的处理函数的注册/关联/定义:
sighandler_t signal(int signum, sighandler_t handler);
signum:需要相应的信号
handler:如何相应/信号处理函数----SIG_DFL(将信号恢复为默认处理) or SIG_IGN(忽略信号)
-----------------------------------------------------------------------------------------------------------------
处理信号的流程:
一个正常的控制流/代码流,从main函数开始执行,然后从main函数返回另一个控制流/代码流,它是由信号引起的一个路径,进入信号处理函数,然后返回到调用它的代码中
-------------------------------------------------------------------------------------------------------------------
信号的发送:
kill():给进程或进程组发送一个信号 int kill(pid_t pid, int sig); pid----正数,要接收信号的进程的pid sig:信号的编号
kill命令是kill函数的一个用户接口 ----0,信号被发送到所有和调用pid进程在统一个进程组的进程
raise():允许进程给自己发送信号 ---- -1,给所有的有权限的进程发送信号
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
signal 出现的问题:
信号排队:等待阻塞
信号处理函数被打断,信号嵌套,递归
不可靠的信号
对信号的操作/处理的3种方法:
1.递归
2.忽略
3.阻塞/等待
sigaction------指定什么信号将被如何处理/指定一个信号的处理函数
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
signum----> 要处理的信号
act----> 指针,指向描述操作的结构 / 指向描述如何响应信号的结构
oldact----> 指针,指向描述被替换操作的结构 / 指向描述被替换的处理设置的结构
struct sigaction {
void (*sa_handler)(int); ---------> 跟signal类似,使用旧处理方式(SIG_DFL,SIG_IGN,处理函数)
void (*sa_sigaction)(int, siginfo_t *, void *); ----------> 新的方式,不但可以得到信号编号,还可以获取被调用的原因以及产生问题的上下文
sigset_t sa_mask; ----------------> 决定在处理一个信号的函数时,是否要阻塞其他信号。sa_mask 的值包括要被阻塞的信号的集合
int sa_flags; ------->SA_RESETHAND:当处理函数被调用时会进行重置 SA_RESTART:当系统调用是针对一些慢速的设备或类似的系统调用,重新开始而不是返回
void (*sa_restorer)(void);
};
一个 sigset_t 是一个抽象的信号量,可以通过一些函数来添加,删除信号的
int sigemptyset(sigset_t *set); // 清除由set指向的集合中的所有信号
int sigfillset(sigset_t *set); //添加所有的信号到set指向的集合
int sigaddset(sigset_t *set, int signum); //添加signum到set指向的集合
int sigdelset(sigset_t *set, int signum); //从set指向的集合中删除signum所标识的信号
======================================================================================================================================================================
临界区:
一段修改一个数据结构的代码,如果在运行时被打断将导致数据的不完整或损坏,那么称这段代码为临界区
阻塞信号:sigprocmask
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); 修改当前的信号掩码/屏蔽字
how------> 如何修改 SIG_BLOCK:添加 SIG_UNBLOCK:删除 SIG_SETMASK:替换/设置
set------> 指向使用的信号集
oldset---------> 指向之前的信号掩码/NULL
*******************************************************************************************************
eg:暂时的阻塞 SIGINT 和 SIGQUIT 信号
sigset_t sigs,prevsigs;
sigemptyset(&sigs); //清空
sigaddset(&sigs,SIGINT); //添加
sigaddset(&sigs,SIGQUIT);
sigprocmask(SIG_BLOCK,&sigs,&prevsigs); //添加阻塞信号
//操作数据结构
sigprocmask(SIG_SETMASK,&prevsigs,NULL); //恢复之前的prevsigs
e14-7: 套接字socket:
============================================================================================================================
| |
| 进程间通信方式总结: |
| |
| 无名管道pipe: 具有亲缘关系的进程间进行使用,单向 |
| |
| 有名管道fifo: 可以用在任意的进程之间,双向,有文件名 |
| |
| 信号signal: 异步,不需要等待 |
| |
| 消息队列msgq: 消息是有类型的 |
| |
| 共享内存share memory: 效率最高,需要同步/互斥机制 |
| |
| 信号量集semaphore: 需要配合共享内存或者公共资源使用,可以实现同步/互斥机制,但是不能单独用于进程间信息的传递 |
| |
| 套接字socket: 可以跨主机进行进程间通信 |
| |
============================================================================================================================
linux进程通信的更多相关文章
- Linux进程通信----匿名管道
Linux进程通信中最为简单的方式是匿名管道 匿名管道的创建需要用到pipe函数,pipe函数参数为一个数组表示的文件描述字.这个数组有两个文件描 述字,第一个是用于读数据的文件描述符第二个是用于写数 ...
- Linux 进程通信之 ——信号和信号量总结
如今最经常使用的进程间通信的方式有:信号,信号量,消息队列,共享内存. 所谓进程通信,就是不同进程之间进行一些"接触",这种接触有简单,也有复杂.机制不同,复杂度也不一 ...
- Linux进程通信学习总结
http://blog.csdn.net/xiaoweibeibei/article/details/6552498 SYSV子系统的相关概念 引用标识符:引用标识符是一个整数,表示每一个SYSV ...
- Linux进程通信的几种方式总结
进程通信的目的 数据传输 一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间 共享数据 多个进程想要操作共享数据,一个进程对共享数据 通知事 一个进程需要向另一个或一组进程发 ...
- linux进程通信之管道
1.介绍: 1)同一主机: unix进程通信方式:无名管道,有名管道,信号 system v方式:信号量,消息队列,共享内存 2)网络通信:Socket,RPC 2.管道: 无名管道(PIPE):使用 ...
- linux 进程通信之 共享内存
共享内存是被多个进程共享的一部分物理内存.共享内存是进程间共享数据的一种最快的方法.一个进程向共享内存区域写入了数据,共享这个内存区域的全部进程就能够立马看到当中的内容. 关于共享内存使用的API k ...
- linux 进程通信 管道
1. 管道概述及相关API应用 1.1 管道相关的关键概念 管道是Linux支持的最初Unix IPC形式之一,具有以下特点: 管道是半双工的,数据只能向一个方向流动:需要双方通信时,需要建立起两个管 ...
- Linux进程通信——管道
管道(pipe)本质上是一种文件,管道通信本质上是通过读写文件通信,但是管道解决了文件的两个问题:限制管道大小,解决read()调用文件结束问题. 管道一个环形的缓冲区,通过两个进程以生产者/消费者的 ...
- 【转】如何基于linux进程通信设计方案
前言 linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的.而对Unix发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在 ...
随机推荐
- 的vim和emacs常用配置记录
因为经常改变工作环境,所以在这里记录一下我的.vimrc文件和.emacs文件的内容. vimrc的配置文件,主要是设置语法高亮,和tab键的宽度,个人喜欢设置为4个空格的分量. " set ...
- Intellij Idea/Webstorm/Phpstorm 的高效快捷键
1. shift + F6可以理解为F2的豪华重量版,不但可以重命名文件名,而且可以命名函数名,函数名可以搜索引用的文件,还可以重命名局部变量.还可以重命名标签名.在sublime text中有个类似 ...
- eclipse启动tomcat, http://localhost:8080无法访问
原地址 症状: tomcat在eclipse里面能正常启动,而在浏览器中访问http://localhost:8080/不能访问,且报404错误.同时其他项目页面也不能访问. 关闭eclipse里面的 ...
- (总结)隐藏PHP版本与PHP基本安全设置
为了安全起见,最好还是将PHP版本隐藏,以避免一些因PHP版本漏洞而引起的攻击. 1.隐藏PHP版本就是隐藏 “X-Powered-By: PHP/5.2.13″ 这个信息. 方法很简单:编辑php. ...
- 小白 安装和配置Tomcat 局域网内访问网页
1.官网http://tomcat.apache.org/ ,下载tomcat,解压就好 2.官网www.oracle.com, 下载javaJDK,截图如下,点击黄色荧光笔
- 虚拟机NAT网络配置
今天虚拟机NAT模式配置网络遇到一个奇葩问题.主机能ping同虚拟机时,虚拟机不能ping同主机.相反虚拟机ping通主机时,主机ping不通虚拟机. 最后花了一个小时,终于可以互通了,做一个记录: ...
- [原创]zepto打造一款移动端划屏插件
最近忙着将项目内的jquery 2换成zepto 因为不想引用过多的zepto包,所以花了点时间 zepto真的精简了许多,源代码看着真舒服 正好项目内需要一个划屏插件,就用zepto写了一个 逻辑其 ...
- basic use of sidekiq (2)
vim Gemfile source "https://rubygems.org" gem "sidekiq"gem 'rack-protection' gem ...
- MetInfo 5.1 自动化getshell工具
title: MetInfo V5.1 GetShell一键化工具 date: 2016-06-08 22:40:32 categories: Hacker tags: - Hacker - Tool ...
- Docker - 入门
术语 1. 镜像(image)与容器(container) 镜像是指文件系统快照或tar包. 容器是指镜像的运行态(时) 2.宿主机管理 设置/配置一台物理服务器或虚拟机,以便用于运行Docker容器 ...