UNIX系统程序设计教程(6)

2019-02-15 23:59

上面的程序中用到了如下函数,我们一一解释一下。

首先是ftok()。它有两个参数,一个是字符串,一个是字符。字符串一般用当前进程的程序名,字符一般用来标记这个标识符所标识的共享内存是这个进程所开辟的第几个共享内存。ftok()会返回一个key_t型的值,也就是计算出来的标识符的值。

其次,操作共享内存,我们用到了下面的函数 #include #include #include

int shmget( key_t shmkey , int shmsiz , int flag );

void *shmat( int shmid , char *shmaddr , int shmflag ); int shmdt( char *shmaddr );

shmget()是用来开辟/指向一块共享内存的函数。参数定义如下:

key_t shmkey 是这块共享内存的标识符。如果是父子关系的进程间通信的话,这个标识符用IPC_PRIVATE来代替。但是刚才我们的两个进程没有任何关系,所以就用ftok()算出来一个标识符使用了。

int shmsiz 是这块内存的大小.

int flag 是这块内存的模式(mode)以及权限标识(关于权限的意思,请参阅本系列第五章)。 模式可取如下值: 新建:IPC_CREAT 使用已开辟的内存:IPC_ALLOC

如果标识符以存在,则返回错误值:IPC_EXCL

然后将“模式” 和“权限标识”进行“或”运算,做为第三个参数。 如: IPC_CREAT | IPC_EXCL | 0666

这个函数成功时返回共享内存的ID,失败时返回-1。

shmat()是用来允许本进程访问一块共享内存的函数。 int shmid是那块共享内存的ID。

char *shmaddr是共享内存的起始地址

int shmflag是本进程对该内存的操作模式。如果是SHM_RDONLY的话,就是只读模式。其它的是读写模式

成功时,这个函数返回共享内存的起始地址。失败时返回-1。

shmdt()与shmat()相反,是用来禁止本进程访问一块共享内存的函数。 参数char *shmaddr是那块共享内存的起始地址。 成功时返回0。失败时返回-1。

此外,还有一个用来控制共享内存的shmctl()函数如下: #include #include #include

int shmctl( int shmid , int cmd , struct shmid_ds *buf ); int shmid是共享内存的ID。

int cmd是控制命令,可取值如下: IPC_STAT 得到共享内存的状态 IPC_SET 改变共享内存的状态 IPC_RMID 删除共享内存

struct shmid_ds *buf是一个结构体指针。IPC_STAT的时候,取得的状态放在这个结构体中。如果要改变共享内存的状态,用这个结构体指定。 返回值: 成功:0 失败:-1

刚才我们的mpaste.c程序中还可以加入这样几句。

struct shmid_ds buf; ... ...

shmctl( shmid , IPC_STAT , &buf ); // 取得共享内存的状态 ... ...

shmctl( shmid , IPC_RMID , &buf ); // 删除共享内存

注意!!!!!!!!!:在使用共享内存,结束程序退出后。如果你没在程序中用shmctl()删除共享内存的话,一定要在命令行下用ipcrm命令删除这块共享内存。你要是不管的话,它就一直在那儿放着了。

简单解释一下ipcs命令和ipcrm命令。

取得ipc信息: ipcs [-m|-q|-s]

-m 输出有关共享内存(shared memory)的信息 -q 输出有关信息队列(message queue)的信息 -s 输出有关“遮断器”(semaphore)的信息 %ipcs -m

删除ipc

ipcrm -m|-q|-s shm_id %ipcrm -m 105

第十章:利用消息队列实现进程间通信

所谓消息功能,是指由一个进程产生并送出的消息,被放在一个叫做“消息队列”的列中管理,然后由接收方从消息队列中取出消息,这么一种功能。(先入先出)

做一个例子程序看看:

下面的两个程序分为发送方和接收方。发送方将自己的PID和从标准输入输入的一个字符串送至消息队列,接收方把消息队列中所有的PID和字符串读出,并输出至标准输出。

/* msend.c */ #include #include #include #include

int main() {

int msqid; key_t msgkey; struct msgbuf {

long mtype;

char mdata[256]; };

struct msgbuf msgdata , *p ;

p = &msgdata ;

printf(Enter message : );

fflush( stdin ); /* 刷新标准输入缓冲区 */

gets( p->mdata ); /* 输入字符串 */ p->mtype = getpid();

msgkey = ftok ( mrecv , 'a' ); /* 计算标识符 */

msqid = msgget( msgkey , IPC_CREAT | 0666 ) ; /* 建立消息队列 */ msgsnd( msqid , p , sizeof(p->mdata) , 0 ); /* 送消息 */ return 0; }

/* mrecv.c */ #include #include #include #include

int main() {

int msqid; key_t msgkey; struct msgbuf {

long mtype;

char mdata[256]; };

struct msgbuf msgdata , *p ; p = &msgdata ;

msgkey = ftok( mrecv , 'a' ); /* 计算标识符 */

msqid = msgget( msgkey , IPC_CREAT | 0666 ) ; /* 取得消息队列的ID */ while(1) {

msgrcv( msqid , p , sizeof(p->mdata) , 0 , 0 ) ; /* 读消息 */

printf(Message received from %ld\\n%s\\n , p->mtype , p->mdata ); }

return 0; }

执行例: % msend

Enter message : Hello , world %msend

Enter message : I am Syuu I

%mrecv

Message received from 321 Hello , world

Message received from 326 I am Syuu I

使用消息功能,可分如下几步 发送方:

1.生成消息队列,取得ID。 2.向消息队列送消息。 接收方:

1.根据标识符,取得ID。 2.从消息队列接收消息。 3.删除消息队列。

例程序相对来说比较简单。我们就不解释了。

消息队列的使用方法以及函数的构造等等基本上和上一章所讲的共享内存的使用方法一样。可参考上一章来理解本章内容。 说说出现的函数:

#include #include

#include

int msgget( key_t msgkey , int flag );

取得一个消息队列的ID,如不存在则建立。 返回值: 成功时:消息队列的ID 失败时:-1

int msgsnd( int msqid , struct msgbuf *msgp , size_t msgsiz , int msgflag ); 向消息队列送消息 返回值: 成功时:0 失败时:-1

msqid是消息队列的ID,size_t msgsiz是结构体成员mdata的大小,msgflag与上一章所讲的共享内存的flag起一样的作用,不过,当这个参数为IPC_NOWAIT的时候,如果消息队列已满,则返回错误值。如果不为IPC_NOWAIT,在消息队列已满 的情况下,会一直等到消息队列有空地方的时候再发送。

注意这里的这个 struct msgbuf *msgp 。要求的格式如下: struct msgbuf {

long mtype;

char mdata[256]; };

long mtype在这里我们用来保存本进程的PID。mdata则是保存要发送的数据。由于mdata的大小不一定(根据实际需要定义),所以这个结构体并没有事先定义好。但是我们定义这个结构体的时候一定要遵循这个规定。你可以改的,只有mdata的大小,和结构体的名称。尽量不要修改结构体成员的名称和类型。实际上,根据mtype,我们还可以有所选择地接受消息。这在下面将会谈到。

int msgrcv( int msqid , struct msgbuf *msgp , size_t msgsiz , long msgtyp , int msgflag ); 从消息队列取得一个消息 返回值: 成功时:0 失败时:-1

msqid , *msgp , msgsiz不用说了。long msgtyp是结构体msgbuf的mtype成员。msgflag与上述一样。只不过为IPC_NOWAIT的时候,如果消息队列是空的,则等到有消息可读的时候再读。当不为IPC_NOWAIT的时候,如果消息队列是空的,则返回错误值(与字面上理解的有些相反)

同样地,为了控制管理消息队列,一样有一个函数msgctl()如下: #include #include #include

int msgctl( int msqid , int cmd , struct msqid_ds *buf ); 返回值: 成功时:0 失败时:-1

cmd所指定的值与共享内存部分相同。

本来还应该有一章关于Semaphore的。其使用方法于共享内存和消息队列差不多,只不过使用场合不同。可是我自己也没太弄明白那个东东是怎么回事,为了避免以讹传讹……就不写了。

看了我这么多贴子,大家辛苦了。《UNIX系统程序设计》这一系列的贴子到此宣告完成。在这些文章的创作过程中得到了SOHU C\\C++论坛诸位朋友的大力支持。在此笔者深表谢意。

接下来,如果有时间的话,我会继续写一套《UNIX网络程序设计(C语言版)》。不知大家有兴趣否。

再有一点。本文中所解释的所有的函数,严格地说,应该叫:系统调用( system call )。

写在后面的话:

UNIX是一个“古老的”,高级的,复杂的,稳定的,有着广泛用户的,难以掌握的,功能强大的,不容易学会的,变态的,操作系统。与Microsoft的windows系列相比,具有对网络更强的操作能力,对进程更强的管理能力,对数据更高的保护能力。然而不幸地,由于windows系列更便利的操作能力对新手的诱惑,国内使用UNIX的人日渐式微。 然而,如果你将来在IT业发展的话,UNIX是必不可少的一门技能。试看当今网络的世界,绝大多数的服务器上仍然是运行着UNIX系的操作系统。UNIX以其强大的功能,广泛的高级用户为基础,在这个MS泛滥的时代依然屹立不倒。

UNIX虽然是一个商业软件,但其发展经历了悠久的年代(在计算机史上绝对可以这样说)。世界各国都有从事UNIX开发的人员。况且还有Linux作为其新生力量,其核心技术的公开性/安全性是以美元为目标的MS所开发的windows所不及的。目前我国有识之士已发出呼吁,建议政府机关/军队等关键部门的计算机采用Linux操作系统,以避免出现紧急情况(战争等)时受制于人。

众所周知,程序开发要分平台,除非你用的是JAVA之类的与平台关系不大的语言。目前在我国,堪称当前技术的生力军、未来技术的主力军的年轻一代计算机专业学生/从业人员/有志者,绝大部分学习/从事着windows平台的程序设计。

诚然,windows平台上也有许多优秀的开发工具,如VC++ , VB , Delphi等等。然而UNIX程序设计的重要性日趋显著。掌握一些UNIX平台上程序设计的基本知识,对于对于程序设计的认识,乃至将来立足于IT业界,都有着重要的影响。


UNIX系统程序设计教程(6).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:小学四年级乘法除法应用题

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: