UNIX环境下如何应用消息队列实现进程间通信
、 消 息 队 列 的 编 程 要 点 及 运 作 过 程
%A
%A ---- 1. 消 息 队 列 的 创 建
%A
%A ---- 在 报 文 能 够 发 送 和 接 收 之 前, 必 须 创 建 一 个 能 够 唯 一 被 识 别 出 的 消 息 队 列 和 数 据 结 构, 这 个 被 创 建 的 唯 一 标 识 符 叫 做 消 息 队 列 描 述 符(msqid), 用 来 识 别 或 引 用 相 关 的 消 息 队 列 和 数 据 结 构。 用msgget(long key, int msgflg) 系 统 调 用 来 创 建 消 息 队 列, 其 中 key 是 一 个 长 整 型, 可 由 用 户 设 定 也 可 通 过ftok() 获 得。msgflg 的 值 是 八 进 制 的 消 息 队 列 操 作 权 和 控 制 命 令 的 组 合。 操 作 权 定 义 为:
%A
%A
%A 操作允许权 八进制整数
%A
%A 用户可读 0400
%A
%A 用户可写 0200
%A
%A 同组可读 0040
%A
%A 同组可写 0020
%A
%A 其它可读 0004
%A
%A 其它可写 0002
%A
%A
%A ---- 操 作 权 可 相 加 而 派 生, 如 用 户 可" 读"、" 写" 的 权 限 为0400|0200=0600。 控 制 命 令 可 取IPC_CREAT 或IPC_EXCL。 如 果 要 创 建 一 个key=888 且 属 主 和 同 组 可 读 写 的 消 息 队 列, 执 行 以 下 系 统 调 用msgget(0x888,0660|IPC_CREAT)。 创 建 后 可 用ipcs 命 令 看 到 以 下 信 息:
%A
%A
%A IPC status from /dev/mem as of Sun
%A
%A Jan 25 06:49:52 1970
%A
%A T ID KEY MODE OWNER GROUP
%A
%A Message Queues:
%A
%A . q 7 0x00000888 --rw-rw----
%A
%A root system
%A
%A ...
%A
%A
%A ---- 它 的 消 息 队 列 描 述 符 是7, 属 主 是root , 同 组 是system, 存 取 权 是 属 主、 用 户 可 读 写。 如 果 执 行msgget(0x888,0660|IPC_CREAT) 时, 与0x888 对 应 的 消 息 队 列 已 存 在, 则 返 回 该 消 息 队 列 的 描 述 符msqid。
%A ---- 2. 消 息 的 发 送
%A
%A ---- 消 息 队 列 一 经 创 建 即 可 用msgsnd(int msqid, void *msgp, size_t msgsz, int msgflg) 发 送 消 息。msgqid 是 经msgget 创 建 的 消 息 队 列 描 述 符,msgp 是 指 向 消 息 段 的 指 针, 该 指 针 所 指 结 构 含 有 报 文 类 型 和 要 发 送 或 接 收 的 报 文:
%A
%A
%A struct msgbuf {
%A
%A long mtype;/*消息类型*/
%A
%A char mtext[512];
%A
%A /* 消息正文,512暂定为消息段的大小*/
%A
%A }
%A
%A ---- msgsz 是msgp 参 量 指 向 的 数 据 结 构 中 字 符 数 组 的 长 度, 即 报 文 长 度, 最 大 值 由MSGMAX 确 定。msgflg 是 当 消 息 队 列 满 时( 队 列 中 无 空 闲 空 间), 系 统 要 采 取 的 行 动. 如 果msgflg&IPC_NOWAIT= 真, 调 用 进 程 立 即 返 回, 不 发 送 该 消 息。 如 果msgflg&IPC_NOWAIT= 假, 调 用 进 程 暂 停 执 行, 处 于" 挂 起" 状 态, 且 不 发 送 该 消 息。 直 到 下 列 情 况 之 一 出 现:
%A ---- - 引 起 暂 停 的 条 件 不 再 存 在, 如 队 列 出 现 空 闲, 即 可 发 送
%A ---- - 该 消 系 队 列 被 从 系 统 中 删 去
%A ---- - 调 用 进 程 接 收 到 一 个 要 捕 捉 的 信 号, 如 中 断 信 号, 此 时 不 发 送 消 息, 调 用 进 程 按signal 中 描 述 的 方 式 执 行。
%A
%A ---- 如 果msgsnd 返 回0 则 发 送 成 功。 返 回-1 则 表 示 发 送 失 败, 错 误 类 型 可 具 体 查 看errno。
%A
%A ---- 3. 消 息 的 接 收
%A
%A ---- 用 msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) 系 统 调 用 从 msqid 消 息 队 列 中 读 取 一 条 信 息 并 将 其 放 入 消 息 段 指 针msgp 指 向 的 结 构。msgsz 给 出mtext 的 字 节 数, 如 果 所 接 收 的 消 息 比msgsz 大 且msgflg&MSG_NOERROR 为 真, 则 按msgsz 的 大 小 截 断 而 不 通 知 调 用 进 程。msgtyp 指 定 要 求 的 消 息 类 型:
%A
%A ---- msgtyp=0 接 收 消 息 队 列 中 的 第 一 个 报 文
%A ---- msgtyp >0 接 收 消 息 队 列 中 的 类 型 为msgtyp 的 第 一 个 报 文
%A ---- msgtyp< 0 接 收 消 息 队 列 中 小 于 等 于msgtyp 绝 对 值 的 最 低 类 型 的 第 一 个 报 文
%A
%A ---- 当 队 列 上 没 有 所 期 望 类 型 的 消 息 或 消 息 队 列 为 空 时msgflg 指 出 调 用 进 程 要 采 取 的 行 动: 如 果msgflg&IPC_NOWAIT 为 真, 则 调 用 进 程 立 即 结 束 并 返 回-1。 如msgflg&IPC_NOWAIT 为 假, 则 调 用 进 程 暂 停 执 行 直 至 出 现:
%A
%A ---- - 队 列 中 放 入 所 需 类 型 的 消 息, 调 用 进 程 接 收 该 消 息
%A ---- -msqid 消 息 队 列 从 系 统 中 删 除
%A ---- - 调 用 进 程 接 收 到 捕 获 的 信 号, 此 时 不 接 收 消 息, 调 用 进 程 按signal 描 述 的 方 式 执 行。
%A
%A ---- 如 果msgrev 执 行 成 功, 则 返 回 放 入mtext 中 的 字 节 数, 失 败 返 回-1 , 错 误 类 型 可 查errno。
%A
%A ---- 4. 消 息 队 列 的 控 制 和 撤 销
%A
%A ---- 用 msgctl(int msqid, int cmd, struct msqid_ds *buf) 系 统 调 用 实 现 对 消 息 队 列 的 控 制。msgqid 必 须 是 用msgget 创 建 的 消 息 队 列 描 述 符。cmd 可 以 是:
%A
%A ---- IPC_STAT 查 看 消 息 队 列 的 状 态, 结 果 放 入buf 指 针 指 向 的 结 构
%A ---- IPC_SET 为 消 息 队 列 设 置 属 主 标 识, 同 组 标 识, 操 作 允 许 权, 最 大 字 节 数
%A ---- IPC_RMID 删 除 指 定 的msqid 以 及 相 关 的 消 息 队 列 和 结 构
%A
%A 四、 编 程 示 例
%A
%A ---- 下 面 给 出 一 个 运 用 消 息 队 列, 实 现 进 程 通 信 的 实 例。 以 下 程 序 在 IBM RS/6000 小 型 机(AIX 操 作 系 统) 上 和IBM PC(UNIX 操 作 系 统) 上 分 别 调 试 通 过。 该 程 序 主 要 模 拟 根 据 帐 号 查 询 余 额 的 过 程。 包 括 三 方 面:
%A
%A 请 求 进 程 从 标 准 输 入 读 入 帐 号, 并 将 该 帐 号 通 过 消 息 队 列 发 送 给 服 务 进 程;
%A
%A 服 务 进 程 接 收 该 帐 号 后, 按 照 请 求 的 先 后 顺 序 在 标 准 输 入 上 输 入 该 帐 户 的 姓 名 和 余 额, 并 将 结 果 返 回 给 客 户 进 程;
%A
%A 请 求 进 程 接 收 返 回 的 信 息, 并 将 结 果 输 出 在 标 准 输 出 上。
%A ---- 服 务 进 程(msgcenter) 先 于 请 求 进 程(msgreq) 启 动. 客 户 进 程 启 动 时 要 携 带 请 求 编 号, 可 同 时 起 动 多 个 请 求 进 程。
%A
%A
%A /*请求方程序msgreq.c*/
%A
%A #include
%A
%A #include
%A
%A #include
%A
%A #include
%A
%A #include
%A
%A static struct msgbuf1{
%A
%A long mtype;
%A
%A char mtext[100];
%A
%A } sndbuf, rcvbuf, *msgp ;
%A
%A extern int errno;
%A
%A main(int argc, char **argv)
%A
%A { int rtrn, msqid ;
%A
%A char name[10];
%A
%A double balance;
%A
%A if (argc!=2){ fprintf(stderr,
%A
%A "msgreq [01-99]\n"); exit(-1); }
%A
%A if ( (msqid = msgget(0x888, IPC_CREAT|0660)) == -1 ){
%A
%A fprintf(stderr, "msgget 888 failed !\n"); exit(-1);
%A
%A }
%A
%A msgp=&sndbuf;
%A
%A sprintf(sndbuf.mtext,"%2.2s",argv[1]);
%A
%A printf("输入4位帐号:");
%A
%A scanf("%s",&sndbuf.mtext[2]);
%A
%A sndbuf.mtext[6]=0;
%A
%A msgp->mtype=666;
%A
%A rtrn=msgsnd(msqid,msgp, strlen(sndbuf.mtext), 0);
%A
%A if (rtrn==-1){
%A
%A perror("msgsnd"); exit(-1);
%A
%A }
%A
%A msgp=&rcvbuf;
%A
%A fprintf(stderr,"等待后台数据处理进程的回答....");
%A
%A rtrn=msgrcv(msqid,msgp, 100, atoi(argv[1]), 0);
%A
%A if(rtrn==-1){ perror("msgrcv"); exit(-1); }
%A
%A sscanf(rcvbuf.mtext,"%[^|]|%lf",name,&balance);
%A
%A printf("\n姓名=%s\n",name);
%A
%A printf("余额=%lf\n",balance);
%A
%A }
%A
%A
%A
%A
%A
%A
%A
%A
%A /*服务方程序msgcenter.c*/
%A
%A #include
%A
%A #include
%A
%A #include
%A
%A #include
%A
%A #include
%A
%A static struct msgbuf1{
%A
%A long mtype;
%A
%A char mtext[100];
%A
%A } sndbuf, rcvbuf , *msgp;
%A
%A extern int errno;
%A
%A main()
%A
%A { int rtrn, msgqid ;
%A
%A char strbuf[100];
%A
%A if ( (msqid = msgget(0x888, IPC_CREAT|0600)) == -1 ){
%A
%A fprintf(stderr, "msgget 888 failed !\n"); exit(-1);
%A
%A }
%A
%A while(1) {
%A
%A msgp=&rcvbuf;
%A
%A fprintf(stderr,"等待前台进程的请求....");
%A
%A rtrn=msgrcv(msqid, msgp, 100, 666 ,MSG_NOERROR);
%A
%A if(rtrn==-1){ perror("msgrcv");exit(-1); }
%A
%A msgp=&sndbuf;
%A
%A sprintf(strbuf,"%2.2s\0",rcvbuf.mtext);
%A
%A msgp->mtype=atoi(strbuf);
%A
%A printf("\n输入帐号=%4.4s的帐户姓名:",&rcvbuf.mtext[2]);
%A
%A scanf("%s",sndbuf.mtext);
%A
%A strcat(sndbuf.mtext,"|");
%A
%A printf("输入该帐户余额:");
%A
%A scanf("%s",strbuf);
%A
%A strcat(sndbuf.mtext,strbuf);
%A
%A rtrn=msgsnd(msqid,msgp, strlen(sndbuf.mtext), 0);
%A
%A if (rtrn==-1){ perror("msgsnd"); exit(-1); }
%A
%A }
%A
%A
%A%A
%A
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。