《unix环境高级编程》通读学习笔记(六)(第15、16章)
上一篇 / 下一篇 2007-08-04 18:08:13 / 个人分类:unix环境高级编程的学习记录
第15章高级进程间通信
15.1引言
本章介绍某些高级的IPC以及它们的应用方法,包括:流管道和命名流管道。使用
be+@H%m;V0这些机制,可以在进程间传送打开文件描述符。在分别为每一个客户进程提供一个通道的系统中,这些通信机制使客户进程能与精灵服务进程会合。
`k"]:_!]%Uz#E ~ l015.2流管道
流管道是一个双向(全双工)管道。单个流管道就能向父、子进程提供双向的数据流。图15-1显示了观察流管道的两种方式。它与图14-1的唯一区别是双向箭头连线,因为流管道是全双工的。
_gnIp cv4s015.3传送文件描述符
在进程间传送打开文件描述符的能力非常有用。用此可以对客户机/服务器应用进行不同的设计。它允许一个进程(一般是服务器)处理与打开一个文件有关的所有操作以及向调用进程返回一描述符,该描述符可被用于以后的所有I/O函数。打开文件或设备的所有细节对客户而言都是透明的。
"L`_rbHlE0当从一个进程向另一个进程传送一打开文件描述符时,我们想要发送进程和接收进程共享同一文件表项。图15-4显示了所希望的安排。
&|A,u0q_+a0本章使用的三个函数以发送和接收文件描述符。
?~1@\9H]$QXu0-------------------------------------------------------------------------------------------------------------------51Testing软件测试网3?@[/ma qp
#include "ourhdr.h"
z6fvVd3Qi!E }"a0int send_fd(intspipefd, int filedes);51Testing软件测试网^ I!u_2k1x
int send_err(int spipefd, int status, const char *errmsg);51Testing软件测试网'f/S(@C m{"yp
两个函数返回:若成功则为0,若出错则为-1
}V5oN)iT\1O0int recv_fd(intspipefd, ssize_t (*userfunc)(int, const void *, size_t));
9O-I%E"i S0返回:若成功则为文件描述符,若出错则<051Testing软件测试网 U/c#fTy
-------------------------------------------------------------------------------------------------------------------51Testing软件测试网f]0Xa/fR
当一个进程(通常是服务器)希望将一个描述符传送给另一个进程时,它调用send_fd或send_err。等待接收描述符的进程(客户机)调用recv_fd。51Testing软件测试网4G!r eVf"Y
send_fd经由流管道spipefd发送描述符filedes。send_err经由流管道spipefd发送errmsg和status字节。status的值应在-1~-255之间.
"WOn#r"v/a0客户机调用recv_fd接收一描述符。如果一切正常(发送者调用了send_fd),则作为函数值返回非负描述符。否则,返回值是由send_err发送的status.51Testing软件测试网^7w8v1f D"~
15.3.1 SVR451Testing软件测试网TZ'Yz7?/aB
在SVR4之下,文件描述符用两个ioctl命令在一流管道中交换,这两个命令是:I_SENDFD和I_RECVFD。51Testing软件测试网.q6y pj/jp-B
15.3.2 4.3BSD
mM[6T&|.C0为了交换文件描述符,调用sendmsg(2)和recvmsg(2)函数。这两个函数的参数中都有一个指向msghdr的指针,该结构包含了所有关于要发送和接收消息的信息。
)o5y4FT$oji v0by015.3.3 4.3+BSD
]ys-Q`5G%I&c0从4.3BSD Reno开始,更改了msghdr结构的定义。在以前版本中被称之为“存取权”的最后两个元素改称为“辅助数据”。另外,在该结构结束处增加了一个新成员msg_flags。
`p[[6cQn015.4 open服务器第1版
目前,使用文件描述符传送技术开发了一个open服务器:它是一个可执行程序,由一个进程执行以打开一个或多个文件。该服务器不是将文件送回调用进程,而是送回一个打开文件描述符。用IPC交换最小量的信息—从客户机到服务器传送文件名和打开方式,而从服务器到客户机返回描述符。文件内容则不需用IPC传送。
2ZdH~ Q0客户机创建一流管道,然后调用fork和exec以调用服务器。客户机经流管道发送请求,服务器经管道回送响应。51Testing软件测试网}&M'B!\9j_V;\P&\3]qO
15.5客户机-服务器连接函数
对于相关进程(例如,父进程和子进程)之间的IPC,流管道非常有用。前节所述的open51Testing软件测试网8t7Dtv5jf){5D @
服务器使用未命名的流管道能从子进程向父进程传送文件描述符。但是当处理无关进程时(例如,若服务器是一精灵进程),则需要使用有名的流管道。
gVQ1awO Yw0服务器创建一名字公开的流管道的一端,然后客户机连接至该端。另外,每次一个新客户机连至服务器的命名流管道时,就在客户机和服务器之间创建一条全新的流管道。SVR4和4.3+BSD都支持这种形式的IPC。本节将开发三个函数,客户机-服务器可以使用这些函数以建立上述针对每个客户机的连接。51Testing软件测试网 { N+{i]'ZMW
--------------------------------------------------------------------------------------------------------------------51Testing软件测试网i-o%N/C"k[5T2q
#include "ourhdr.h"
t!K-Q_t)A0int serv_listen(const char *name);51Testing软件测试网-[X)@z^hce+l)TS
返回:若成功则返回为文件描述符,若出错则<051Testing软件测试网"L @@V*}EN)I
-------------------------------------------------------------------------------------------------------------------51Testing软件测试网@5f_%Vc u
首先,一个服务器应当宣布,它愿意听取客户机在一个众所周知名字上的连接,该名字是在文件系统中的一个路径名。为此调用serv_listen,其参数name是服务器的众所周知名字。客户机希望与服务器连接时使用此名字。该函数的返回值是命名流管道服务器端的文件描述符。
K[Z`"F`P0一旦服务器已调用serv_listen,它将调用serv_accept等待客户连接到达。
V [Et5W5kLQn6j(~0---------------------------------------------------------------------------------------------------------------------
1uV rzQu0#include "ourhdr.h"51Testing软件测试网2by ]%|[e
int serv_accept(int listenfd, uid_t *uidptr);51Testing软件测试网/K!D F8o,Wr q)m
返回:若成功则返回为文件描述符,若出错则<051Testing软件测试网&b E|5H8b
--------------------------------------------------------------------------------------------------------------------
lB*d1tZ.H0listenfd是serv_listen返回的描述符。在客户机连接到服务器众所周知的名字上之前,此函数并不返回。当客户机连接至服务器时,自动创建一条全新的流管道,其新描述符作为该函数的值返回。另外,客户机的有效用户ID通过指针uidptr存储。
1`ZGqT x4QN0客户机为与服务器连接只需调用cli_conn函数。51Testing软件测试网#z7u)ha WV+I!H"J
------------------------------------------------------------------------------------------------------------------
tf.H^RK+z$KgRg0#include "ourhdr.h"
,I!N}0e P0int cli_conn(const char * name);51Testing软件测试网D9I@n)^ o.R
返回:若成功则返回为文件描述符,若出错则<051Testing软件测试网:Eqg)B_9S
-------------------------------------------------------------------------------------------------------------------
3a3ai!C5y]qY0使用上述三个函数,就可编写服务器精灵进程,它可以管理任一数量的客户机。51Testing软件测试网9aC)~ oy;O
15.5.1 SVR4
:Dj%ppz Wn0SVR4提供装配的流以及一个名为connld的流处理模块,用其可以提供与服务器有唯一连接的命名流管道。
2}9oq&aU?(|v!c+{0首先,服务器创建一未命名流管道,并将流处理模块connld压入一端。图15-5显示了这一处理结果。然后,使压入connld的一端具有一路径名。SVR4提供fattach函数实现这一点。任一进程(例如客户机)打开此路径名就引用该管道的命名端。51Testing软件测试网4EI+x8O#_Yl#^g
15.5.2 4.3+BSD
1j5Gd.\_A%e1Chy9g ~`0在4.3+BSD之下,为了用UNIX域套接口连接客户机和服务器,需要有一套不同的操作函数。
'[W/~K3H\Q/w0Z"x015.6 open服务器第2版
在15.4节中,客户机调用fork和exec构造了一个open服务器,它说明了如何从子程序向父程序传送文件描述符。本节将开发一个精灵进程样式的open服务器。一个服务器处理所有客户机的请求。在客户机和服务器之间仍将使用上一节说明的三个函数:serv_listen、serv_accept和cli_conn。本节所述的客户机类似于15.4节中的客户机。51Testing软件测试网 |?I6G1`y/n
第16章数据库函数库
16.1引言
80年代早期,UNIX环境被认为不适合运行多用户数据库系统。早期的系统,如V7,因为没有提供任何形式的IPC机制(除了半双工管道),也没有提供任何形式的记录锁机制,所以确实不适合运行多用户数据库。新一些的系统,象SVR4和4.3+BSD,则为运行可靠的、多用户的数据库系统提供了一个适合的环境。
.Nmg+hReU!g0本章将设计一个简单的、多用户数据库的函数库。通过此函数库提供的C语言函数,其他程序可以访问数据库中的记录。我们感兴趣的是一个数据库函数库与UNIX的接口,以及这些接口与前面各章节的关系。
2s#qG0S;Y@ Aq P-V/IY016.2历史
16.3函数库
本节将定义数据库函数库的C语言接口,下一节再讨论其实现。51Testing软件测试网}.|9TWj
当打开一个数据库时,通过返回值得到一个DB结构的指针。我们将用此指针作为参数来调用以后的数据库函数。51Testing软件测试网D V!g/ZD
----------------------------------------------------------------------------------------------------------------------
V"\4NR3?9WOKW"E0#include "db.h"
(~s%t*{tg0DB *db_open(const char *pathname, int oflag, int mode);
L/cF2Mi ]dQ0返回:若成功则为DB结构的指针,若失败则为NULL51Testing软件测试网LW \\s L,H
void db_close(DB *db);51Testing软件测试网?.X;@W TPT
---------------------------------------------------------------------------------------------------------------------
]b z fYT0当不再使用数据库时,调用db_close来关闭数据库。db_close将关闭索引文件和数据文件,并释放数据库使用过程中分配的所有用于内部缓冲的存储空间。
%};YP6qVptQ0当向数据库中加入一条新的记录时,必须提供一个此记录的关键字,以及与此关键字相联系的数据。我们的实现要求关键字必须是唯一的。51Testing软件测试网[c8a0`&M
---------------------------------------------------------------------------------------------------------------------51Testing软件测试网4H GnK m'LbY
#include "db.h"51Testing软件测试网?Y c6O)H a2qZ
int db_store(DB *db,const char *key, const char *data, int flag);
I.EA3J!I`9W0返回:若成功则为0,若错误则为非0(见下)
{0kN|.cYW0----------------------------------------------------------------------------------------------------------------------
5j*A2Si O#d0通过提供关键字key可以从数据库中取出一条记录。51Testing软件测试网veC:jEF$uKV
---------------------------------------------------------------------------------------------------------------------51Testing软件测试网;xmR;H\V
#include "db.h"51Testing软件测试网,^I1|;n6@3I,@8Go#T
char *db_fetch(DBdb*,const char *key,);51Testing软件测试网sqdQ9Y9aX"L#Fw*D5^
返回:若成功则为指向数据的指针,若记录没有找到则为NULL51Testing软件测试网"e&NDxi6lc
----------------------------------------------------------------------------------------------------------------------
V"j ^n7F2GK5I0通过提供关键字key,也可以从数据库中删除一条记录。51Testing软件测试网+h0Q^ b7nWn%GL
----------------------------------------------------------------------------------------------------------------------51Testing软件测试网A+M0V`b
#include "db.h"
0^#~ at`E2?#]_%^-l0int db_delete(DBdb*,const char *key);
b]!C([+uOpNS bN0返回:若成功则为0,若记录没有找到则为-151Testing软件测试网l#i3@I DlMk D
----------------------------------------------------------------------------------------------------------------------51Testing软件测试网G DvqR(@$F
除了通过关键字访问数据库外,也可以一条一条记录地访问数据库。因此,首先调用
d~4[x8p+tk0db_rewind回到数据库的第一条记录,再调用db_nextrec顺序地读每个记录。51Testing软件测试网-t9n2O4Y!h5qm!Q5a
----------------------------------------------------------------------------------------------------------------------51Testing软件测试网1R7G,S(s1nd
#include "db.h"51Testing软件测试网H$H6o%W.q?&Mb
void db_rewind(DBdb*)
;~0zz)J/@6WZU0char *db_nextrec(DBdb*, char*key);51Testing软件测试网MSkS4M*k NkVo
返回:若成功则返回指向数据的指针,若到达数据库的尾端则为NULL51Testing软件测试网d-h^V0\\-Gq+j
----------------------------------------------------------------------------------------------------------------------
!Up{C.z w#qtg~0这七个函数提供了数据库函数库的接口。接下来介绍实现。51Testing软件测试网rq ^DqU7D-Zf
16.4实现概述
大多数数据库访问的函数库使用两个文件来存储信息:一个索引文件和一个数据文件。索引文件包括索引值(关键字)和一个指向数据文件中对应数据记录的指针。有许多技术可用来组织索引文件以提高按关键字查询的速度和效率,散列表和B+树是两种常用的技术。我们采用固定大小的散列表来组织索引文件结构,并采用链表法解决散列冲突。
0f!t$Cuc6Ap0图16-1是数据库实现的基本结构。索引文件由三部分组成:空闲链表指针、散列表和索引记录。
&T'QRV#pvs016.5集中式或非集中式
当有多个进程访问数据库时,有两种方法可实现库函数:51Testing软件测试网8eGt^/r9[
(1)集中式由一个进程作为数据库管理者,所有的数据库访问工作由此进程完成。库函数通过IPC机制与此中心进程进行联系。
v$}5D2P|v!G?C0QI0(2)非集中式每个库函数独立申请并发控制(加锁),然后调用它自己的I/O函数。51Testing软件测试网+aW(Q1D]uX
使用这两种技术的数据库都有。UNIX系统中的潮流是使用非集中式方法。如果有适当的加锁函数,因为避免使用了IPC,那么非集中式方法一般要快一些。图16-2描绘了集中式方法的操作。
~W Cmoq5D0集中式的优点是能够根据需要来对操作模式进行控制。51Testing软件测试网p p"z?3@.j/]M&p
图16-3描绘了非集中式方法,本章的实现就是采用这种方法。使用库函数访问数据库的用户进程是平等的,它们通过使用记录锁机制来实现并发控制。
v2}7N`%CoHH g.`016.6并发
由于很多系统的实现都采用两个文件(一个索引文件和一个数据文件)的方法,所以我们也使用这种方法,这要求我们能够控制对两个文件的加锁。有很多方法可用来对两个文件进行加锁。
'lXRLMq016.6.1粗锁
c N#Z3sx,OS0最简单的加锁方法是将这两个文件中的一个作为锁,并要求调用者在对数据库进行操作前必须获得这个锁。我们将这称为粗锁(coarse locking)。
9oAX ]\Vc0粗锁的问题是它限制了最大程度的并发。用粗锁时,当一个进程向一条散列链中加一条记录时,其他进程无法访问另一条散列链上的记录。
&u7X5Ch1w#VnF016.6.2细锁51Testing软件测试网rf'm/]0m1w6\0r p
下面用称为细锁(fine locking)的方法来加强粗锁以提高并发度。我们要求一个读进程或写进程在操作一条记录前必须先获得此记录所在散列链的读锁或写锁。允许对一条散列链同时可以有多个读进程,而只能有一个写进程。51Testing软件测试网lrQ-xh#y
16.7源码
16.8性能
16.8.1单进程的结果51Testing软件测试网9VZp`!D`oM
16.8.2多进程的结果
,e&R oiB7wEA0TAG:
我的栏目
标题搜索
日历
|
|||||||||
日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
1 | 2 | 3 | 4 | 5 | 6 | ||||
7 | 8 | 9 | 10 | 11 | 12 | 13 | |||
14 | 15 | 16 | 17 | 18 | 19 | 20 | |||
21 | 22 | 23 | 24 | 25 | 26 | 27 | |||
28 | 29 | 30 |
我的存档
数据统计
- 访问量: 158045
- 日志数: 220
- 图片数: 4
- 文件数: 1
- 书签数: 16
- 建立时间: 2007-04-27
- 更新时间: 2012-01-30