需求报告书21Word格式文档下载.docx
《需求报告书21Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《需求报告书21Word格式文档下载.docx(33页珍藏版)》请在冰豆网上搜索。
消息实质上就是一些字或字节的序列(未必以空字符结尾),它通过消息队列的方法在进程间传递。
而一个消息队列包含若干个消息数据结构,每个队列中的消息数据结构的基本属性包括消息类型,消息大小,消息内容指针和下一个消息数据结构位置
3
共享内存
Sharedmemory
共享内存允许两个或多个进程共享一定的存储区,因为不需要拷贝数据,所以这是最快的一种IPC。
4
信号
Signal
信号是进程间通信机制中唯一的异步通信机制,可以看作是异步通知,通知接收信号的进程有哪些事情发生。
5
管道
Pipe
一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。
6
有名管道
Namedpipe
半双工的通信方式,但是它允许无亲缘关系进程间的通信。
7
IPC
Inter-ProcessCommunication
进程间通信
8
内核
Kernel
Linux系统核心
9
先入先出队列
FIFO
FirstInputFirstOutput的缩写
10
亲缘关系
Relative
指两个进程有共同的祖先
11
系统调用
Systemcall
由操作系统实现提供的所有系统调用所构成的集合即程序接口或应用编程接口,是应用程序同系统之间的接口
12
内存管理单元
MMU
它是中央处理器(CPU)中用来管理虚拟存储器、物理存储器的控制线路,同时也负责虚拟地址映射为物理地址,以及提供硬件机制的内存访问授权
13
可移植操作系统接口
POSIX
POSIX标准定义了操作系统应该为应用程序提供的接口标准,是IEEE为要在各种UNIX操作系统上运行的软件而定义的一系列API标准的总称
14
缓冲区
Buffer
暂存数据
1.3文档概述
本文档是对Linux进程通信模块的需求分析和规格说明书,主要借助RUCM结构化模板,采用用例图等形式进行分析。
1.4模块概述
Linux使用的进程间通信方式:
(1)管道(pipe)与有名管道(namedpipe):
管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。
进程的亲缘关系通常是指父子进程关系。
有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
(2)信号量(semaphore):
信号量是一个计数器,可以用来控制多个进程对共享资源的访问。
它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。
因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
(3)消息队列(messagequeue):
消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。
消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
(4)信号(signal):
信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
(5)共享内存(sharedmemory):
共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。
共享内存是最快的IPC方式,它是针对其他进程间通信方式运行效率低而专门设计的。
它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
2典型应用场景分析
2.1管道和有名管道
管道主要用于父进程与子进程之间,或者两个兄弟进程之间。
首先,由父进程创建一个管道后通过系统调用产生子进程。
接着,父进程关闭这个通道的读出端,子进程关闭同一通道的写入端。
这就在父子进程间提供了一个单向数据流。
管道是在内核中的数据结构,所以子进程不会复制管道。
但管道的文件描述符在进程空间中,所以子进程获得了管道的文件描述符副本。
有名管道是为了解决无名管道只能用于近亲进程之间通信的缺陷而设计的。
有名管道是建立在实际的磁盘介质或文件系统(而不是只存在于内存中)上有自己名字的文件,任何进程可以在任何时间通过文件名或路径名与该文件建立联系。
有名管道常被用在shell命令行将数据从一条命令传送到另一条命令,而不需要创建中间的临时文件,以及在客户--服务器结构中,使用有名管道在客户和服务器之间交换数据
2.2消息队列
消息队列的一个典型应用场景就是对称多处理机器。
运行在一个CPU上的调度程序把工作请求发送到一个特定的消息队列上。
工作请求可能以各种形式出现:
用来破译代码的一组密码、需要进行计算的在不规则图形里的象素范围、在一个原子系统里要更新的一部分空间,或者诸如此类的任务。
与此同时,工作者进程在其它CPU上运行,只要它们空闲就从消息队列中检索消息,然后再把结果消息发送到另一个消息队列上去。
这种体系结构很容易实现,而且假定选择好了每个消息中被请求工作的粒度,就能极大的提高机器中CPU的利用效率。
(还要注意的是,因为调度进程可能不用做许多工作,所以调度进程的CPU上大部分时间也可以运行一个工作者进程。
)以这种方式,消息队列可以被用作是远程过程调用(RPC)的一种低级形式。
2.3共享内存
共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。
它是最快的IPC方式,是针对其他进程间通信方式运行效率较低而专门设计的。
应用过程举例:
两个程序A、B通过命令行参数指定同一个文件来实现共享内存方式的进程间通信。
1)由一个进程对共享内存作出修改;
程序B试图打开命令行参数指定的一个普通文件,把该文件映射到进程的地址空间,并对映射后的地址空间进行写操作。
2)所有其它进程只需通过一个指向共享内存空间的指针来读取,就可立即可见结果。
程序A把命令行参数指定的文件映射到进程地址空间,然后对映射后的地址空间执行读操作。
这样,两个进程通过命令行参数指定同一个文件来实现共享内存方式的进程间通信。
2.4信号量
信号量是一个计数器,可以用来控制多个进程对共享资源的访问。
假设你有很多相互协作的进程,它们正在读或写一个数据文件中的记录。
1)你希望严格协调对这个文件的存取,于是你使用初始值为1的信号量。
(在这个信号量上实施两个操作,首先测试并且给信号量的值减1,然后测试并给信号量的值加1。
)
2)当第一个进程存取文件时,它把信号量的值减1,并获得成功,信号量的值现在变为0,这个进程可以继续执行并存取数据文件。
3)如果另外一个进程也希望存取这个文件,那么它也把信号量的值减1,结果是不能存取这个文件,因为信号量的值变为-1。
这个进程将被挂起,直到第一个进程完成对数据文件的存取。
4)当第一个进程完成对数据文件的存取,它将增加信号量的值,使它重新变为1,现在,等待的进程被唤醒,它对信号量的减1操作将获得成功。
2.5信号
信号事件的发生总体上来说有两个来源:
硬件来源和软件来源
具体来讲:
1)用户在终端按下某些键时,终端驱动程序会发送信号给前台进程
2)硬件异常产生信号,这些条件由硬件检测到并通知内核,然后内核向当前进程发送适当的信号。
例如当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释为SIGFPE信号发送给进程。
再比如当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给当前进程
3)进程之间通过调用系统函数发送信号,主要包括kill()、raise()、sigqueue()、alarm()、setitimer()以及abort()。
4)当内核检测到某种软件条件发生时也可以通过信号通知进程,例如闹钟超时产生SIGALRM信号,向读端已关闭的管道写数据时产生SIGPIPE信号
3功能需求
3.1功能需求概述
(1)数据传输:
一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间;
(2)共享数据:
多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到;
(3)通知事件:
一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程);
(4)资源共享:
多个进程之间共享同样的资源。
为了作到这一点,需要内核提供锁和同步机制;
(5)进程控制:
有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。
3.2管道
管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。
进程的亲缘关系通常是指父子进程关系
3.3有名管道
有名管道是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
3.4消息队列
消息队列(messagequeues)是进程之间互相发送消息的一种异步(asynchronously)方式,在这种情形之下,发送方不必等待接收方检查它的消息——即在发送完消息后,发送方就可以从事其它工作了——而接收方也不必一直等待消息。
对消息进行编码和解码是发送者和接受者进程的工作;
消息队列的执行并不会给它们特别的帮助。
这就形成了一个实现起来相对比较简单的通用机制,尽管是以增加应用程序的复杂度为代价来获得这种简明性的。
有足够写权限的进程可往队列中放置消息,有足够读权限的进程可从队列中取走消息。
每个消息是一个记录它由发送者赋予一个优先级。
在某个进程往一个队列写入消息之前,并不需要另外某个进程在该队列上等待消息的到达,这跟管道和FIFO是相反的,对后者来说,除非读出者已存在,否则先有写入者是没有意义的。
消息队列是随内核持续的,只有在内核重起或者显示删除一个消息队列时,该消息队列才会真正被删除。
因此系统中记录消息队列的数据结构位于内核中,系统中的所有消息队列都可以在该数据结构中找到访问入口。
一个进程可以先往某个队列写入一些消息后终止,让另外一个进程在以后某个时刻读出这些消息。
这一点管道和FIFO是不支持的。
一个或多个进程可向消息队列写入消息,而一个或多个进程可从消息队列中读取消息,这种进程间通讯机制通常使用在客户/服务器模型中,客户向服务器发送请求消息,服务器读取消息并执行相应请求。
在许多微内核结构的操作系统中,内核和各组件之间的基本通讯方式就是消息队列。
新消息总是加在队列的末尾,不过它们并不总是从排头移出;
消息可以从队列的任何地方被移出。
在某个方面,消息队列与语音邮件类似:
新消息总是在末尾,不过消息接收方可以从列表的中间接收(以及删除)消息。
消息队列分为公有消息队列和私有消息队列。
如果是公有消息队列,则系统中所有的进程通过权限检查后,通过统一的公有标志均可以找到系统消息队列对象的引用标识符。
消息队列与管道以及有名管道相比,具有更大的灵活性,首先,它提供有格式字节流,有利于减少开发人员的工作量;
其次,消息具有类型,在实际应用中,可作为优先级使用。
这两点是管道以及有名管道所不能比的。
同样,消息队列可以在几个进程间复用,而不管这几个进程是否具有亲缘关系,这一点与有名管道很相似;
但消息队列是随内核持续的,与有名管道(随进程持续)相比,生命力更强,应用空间更大。
1)获取消息队列
消息队列就是一个消息的链表,是内存中独立于生成它的进程的一段存储区,是内核地址空间中的内部链表。
2)发送消息
a)当某个进程要写入消息时,该进程的有效用户id和组id首先要和ipc_perm中的访问模式进行比较。
如果进程不能写入,系统调用返回错误,写操作结束。
b)如果该进程可以向消息队列写入,则消息可以复制到消息队列的末尾。
在进行复制之前,必须判断消息队列当前是否已满。
消息的具体内容和应用程序有关,由参与通讯的进程约定。
c)如果消息队列中当前没有空间容纳消息,则写入进程被添加到该消息队列的写等待队列,否则,内核分配一个消息结构,将消息从进程的地址空间中复制到消息结构,然后将该消息添加到队列末尾,这时,系统调用成功返回,写操作结束。
d)调用调度程序,调度程序选择其他进程运行,写操作结束。
如果有某个进程从消息队列中读取了消息,则系统会唤醒写等待队列中的进程。
读取操作和写入操作类似,但进程在没有消息或没有指定类型的消息时进入等待状态。
3)接收消息
一个或多个进程可从消息队列中读取消息,消息可以从队列的任何地方被移出。
有足够读权限的进程才可从队列中取走消息。
接收消息时消息队列为空时,若接收进程指定不等待,则只返回一个参数;
若指定等待,则轮询该消息队列,直到有指定类型的消息到来时,进程接收消息。
4)控制消息
包括获取消息队列信息,设置消息队列的属性,删除指定id的消息队列。
其属性信息存储在一个单独的结构体中,里面包括用户id、组id、访问模式和字节数。
a)获取消息队列状态信息
b)设置消息队列属性
c)删除消息队列
3.5共享内存和信号量
共享内存和信号量经常配合使用,下面重点介绍共享内存
1)获取共享内存
2)读取共享内存
3)写入共享内存
4)释放共享内存
3.6信号
当以信号的方式实现进程通信时,首先信号源(进程、内核和硬件)产生一个信号,然后信号需要进行注册,最后接收进程对信号进行处理,处理之前信号会被注销。
信号的产生
1)内核产生信号
2)硬件产生信号
3)进程产生信号
信号的发送
1)信号的注册
2)信号屏蔽
信号的读取
处理信号
1)注销信号
2)运行处理函数
管理信号队列
1)管理屏蔽信号集
2)管理阻塞信号集
4非功能性需求分析
4.1鲁棒性
鲁棒性就是系统的健壮性,它是在异常和危险情况下系统生存的关键,就进程通信来讲,我们知道,在某些异常情况下,进程通信能够及时的反馈错误信息。
如:
在信号接收进程处理信号函数的过程中,可能发生异常,导致函数不能成功的执行,这时进程就会返回错误信息给信号源,使信号源知道信号发送失败。
在共享变量创建子用例中,内核可能会检测到异常错误信息,比如内存分配失败,然后返回错误信息给进程,进程继续自主操作。
对消息队列进行操作时,例如往满队列写入消息或者从空队列读入消息可能造成的错误,此时记录该错误,并将该错误返回给相应进程进行处理,保证了程序的健壮性
4.2安全性
就消息队列而言,有足够写权限的进程可往队列中放置消息,有足够读权限的进程可从队列中取走消息。
在共享内存中,SystemV共享内存没有确保互斥的内置方案:
一个进程可以向共享内存中的给定地址写入而同时另一个进程从相同的地址读出,由于不是原子操作并且没有提供锁操作,这会导致读者所看到的将是不一致的数据。
这使得我们在使用共享内存进行进程间通信时,往往要借助其他的手段来进行进程间的同步工作,比如信号量、互斥锁等。
就信号机制而言,首先当信号源通过系统调用向目标进程发送信号时,都会明确标明进程或进程组的ID,这就保证了该信号只会发送给相关的进程,其次进程维护的信号队列是私有的,非本进程不能从该队列中获取信号。
以上两点保证了信号机制的安全性。
管道只能在有亲缘关系的进程间共享数据,相互通信的进程都具有相同的祖先,有亲缘关系的进程间通信是安全的,因而不需要对管道提供额外的安全性控制。
有名管道与管道不同,有名管道需要在创建时由创建者为其设定访问权限,保存在系统为有名管道维护的数据结构中,当某一进程需要打开或存取某一FIFO文件时,内核将对该用户进行权限检查来判断当前的操作是否允许。
4.3效率
共享内存是最快的一种IPC方式,它会映射到进程的虚拟地址空间,进程对其可以直接访问,避免了数据的复制过程。
进程可以直接读写内存,而不需要任何数据的拷贝。
对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据:
一次从输入文件到共享内存区,另一次从共享内存区到输出文件。
例如使用消息队列时,一个进程要向队列中写入消息,要引起从用户地址空间向内核地址空间的一次复制,同样一个进程进行消息读取时也要进行一次复制。
共享内存的优点是完全省去了这些操作。
4.4约束
管道和有名管道的主要约束正体现在它的特点上:
1)只支持单向数据流;
2)缓冲区有限(管道制存在于内存中,在管道创建时,为缓冲区分配一个页面大小);
3)传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式,比如多少字节算作一个消息(或命令、或记录)等等;
管道在其上还有另外两个约束:
4)只能用于具有亲缘关系的进程之间;
5)没有名字;
消息队列的限制:
默认情况下,整个系统中最多只能有16个消息队列,每个消息队列最大为16384个字节,消息队列中每个消息最大为8192个字节。
信号的约束性在于存在可靠信号与不可靠信号,不可靠信号即:
1)进程每次处理信号后,就将对信号的响应设置为默认动作。
在某些情况下,将导致对信号的错误处理
2)信号可能丢失
随着时间的发展,实践证明了有必要对信号的原始机制加以改进和扩充。
所以,后来出现的各种Unix版本分别在这方面进行了研究,力图实现"
可靠信号"
。
由于原来定义的信号已有许多应用,不好再做改动,最终只好又新增加了一些信号,并在一开始就把它们定义为可靠信号,这些信号支持排队,不会丢失。
同时,信号的发送和安装也出现了新版本:
信号发送函数sigqueue()及信号安装函数sigaction()。
POSIX.4对可靠信号机制做了标准化。
5参考文献
[1]
[2]毛德操.Linux内核源代码情景分析.浙江大学出版社[M].第一版(20019月1日)
[3]
[4]
[5]
[6]
[7]
[8]赵炯.Linux内核完全注释.机械工业出版社[M].2004-9-1.