APUE读书笔记-第15章-进程间通信

15.1 引言

*进程之间交换信息的方法可以经由fork或exec传送打开文件,或者通过文件系统

*进程之间相互通信的其他技术——IPC(InterProcess Communication)包括半双工管道、FIFO、全双工管道、命名全双工管道、消息队列、信号量、共享存储、套接字、STREAMS


15.2 管道

*管道有两种局限性:(1)历史上,它们是半双工的(即数据只能在一个方向上流动)(2)它们只能在具有公共祖先的进程之间使用

*每当你在管道线中键入一个由shell执行的命名序列时,shell为每一条命令单独创建一进程,然后将前一条命令进程的标准输出用管道与后一条命令的标准输入相连接

*管道是由调用pipe函数而创建的


15.3 popen和pclose函数

*常见的操作是创建一个管道连接到另一个进程,然后读其输出或向其输入端发送数据。为此,标准I/O库提供了两个函数popen和pclose。这两个函数实现的操作是:创建一个管道,调用fork产生一个进程,关闭管道的不使用端,执行一个shell以运行命令,然后等待命令终止


15.4 协同进程

*UNIX系统过滤程序从标准输入读取数据,对其进行适当处理后写到标准输出。几个过滤程序通常在shell管道命令行中线性的连接。当一个程序产生某个过滤程序的输入,同时又读取该过滤程序的输出时,则该过滤程序就称为协同进程(coprocess)

*标准I/O的缓冲机制问题的解决方法是使被调用的协同进程(在本例中是awk)认为它的标准输入和输出都被连接到一个终端


15.5 FIFO

*FIFO有时被称为命名管道。管道只能由相关进程使用,这些相关进程的共同的祖先进程创建了管道。(一个例外是已装配的基于STREAMS的管道)。但是,通过FIFO,不相关的进程也能交换数据。

*FIFO有下面两种用途:

(1)FIFO由shell命令使用以便将数据从一条管道线传送到另一条,为此无需创建中间临时文件

(2)FIFO用于客户进程-服务器进程应用程序中,以在客户进程和服务器进程之间传递数据


15.6 XSI IPC

*有三种IPC我们称作XSI IPC,即消息队列、信号量以及共享存储器,它们之间有很多相似之处

*每个内核中的IPC结构(消息队列、信号量或共享存储段)都用一个非负整数的标识符(identifier)加以引用

*标识符是IPC对象的内部名。为使多个合作进程能够在同一IPC对象上会合,需要提供一个外部名方案。为此使用键(key),每个IPC对象都与一个键相关联,于是键就用作为该对象的外部名

*有多种方法可以使客户进程和服务器进程在同一IPC结构上会合:

(1)服务器进程可以指定键IPC_PRIVATE创建一个新IPC结构,将返回的标识符存放在某处(例如一个文件)以便客户进程取用。键IPC_PRIVATE保证服务器进程创建一个新IPC结构。IPC_PRIVATE键也可用于父子进程关系。父进程指定IPC_PRIVATE创建一个新IPC结构,所返回的标识符在调用fork之后可由子进程使用。接着,子进程又可将此标识符作为exec函数的一个参数传给一个新程序

(2)在一个公用头文件中定义一个客户进程和服务器进程都认可的键。然后服务器进程指定此键创建一个新的IPC结构

(3)客户进程和服务器进程认同一个路径名和项目ID(项目ID是0~255之间的字符值),接着调用函数ftok将这两个值变换为一个键。然后在方法(2)中使用此键。ftok提供的唯一服务就是由一个路径名和项目ID产生一个键


15.7 消息队列

*msgget创建一个新队列或打开一个现存的队列。msgsnd将新消息添加到队列尾端。每个消息包含一个正长整数类型字段,一个非负长度以及实际数据字节(对应于长度),所有这些都在讲消息添加到队列时,传送给msgsnd。msgrcv用于从队列中取消息。

*每个消息由三部分组成,它们是:正长整型类型字段、非负长度(nbytes)以及实际数据字节(对应于长度)。消息总是放在队列尾端

*若消息队列已满(或者是队列中的消息总数等于系统限制值,或队列中的字节总数等于系统限制值),则指定IPC_NOWAIT使得msgsnd立即出错返回EAGAIN。如果没有指定IPC_NOWAIT,则进程阻塞直到下述情况出现为止:有空间可以容纳要发送的消息;从系统中删除了此队列,或捕捉到一个信号,并从信号处理程序返回。


15.8 信号量

*信号量(semaphore)与已经介绍过的IPC机构(管道、FIFO以及消息队列)不同。它是一个计数器,用于多进程对共享数据对象的访问


15.9 共享存储

*共享存储允许两个或更多进程共享一给定的存储区。因为数据不需要在客户进程和服务器进程之间复制,所以这是最快的一种IPC。使用共享存储时要掌握的唯一窍门是多个进程之间对一给定存储区的同步访问,若服务器进程正在将数据放入共享存储区,则它做完这一操作之前,客户进程不应当去取这些数据。通常,信号量被用来实现对共享存储访问的同步。(记录锁也可用于这种场合)

*为了获得一个共享存储标识符,调用的第一个函数通常是shmget

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

*shmctl函数对共享存储段执行多种操作

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

*cmd参数指定下列5种命令中一种,使其在shmid指定的段上执行

IPC_STAT

IPC_SET

IPC_RMID 从系统中删除该共享存储段

SHM_LOCK 将共享存储段锁定在内存中

SHM_UNLOCK 解锁共享存储段

*一旦创建了一个共享存储段,进程就可调用shmat将其连接到它的地址空间中

void *shmat(int shmid, const void *addr, int flag)

共享存储段连接到调用进程的哪个地址上与addr参数以及在flag中是否制定SHM_RND位有关

(1)如果addr为0,则此段连接到由内核选择的第一个可用地址上

(2)如果addr非0,并且没有指定SHM_RND,则此段连接到addr所指定的地址上

(3)如果addr非0,并且指定了SHM_RND,则此段连接到(addr-(addr mod ulus SHMLBA))所表示的地址上。SHM_RND命令的意思是“取整”。SHMLBA的意思是“低边界地址倍数”,它总是2的乘方

*shmat的返回值是该段所连接的实际地址,如果出错则返回-1

*当对共享存储段的操作已经结束时,则调用shmdt脱接该段

int shmdt(void *addr)

*很多实现提供了一种类似于/dev/zero的设施,称为匿名存储映射


15.10 客户进程-服务器进程属性

*客户进程和服务器进程的某些属性受到它们之间所使用的IPC类型的影响。最简单的关系类型是使客户调用fork然后调用exec执行所希望的服务器进程。在fork之前先创建两个半双工管道使数据可在两个方向传输

你可能感兴趣的:(通信,读书笔记,服务器,存储,行业数据)