weidagang2046的專欄

          物格而后知致
          隨筆 - 8, 文章 - 409, 評論 - 101, 引用 - 0
          數據加載中……

          UNIX環境下如何應用消息隊列實現進程間通信

          一、 引 言

          ---- 進 入 九 十 年 代 后, 隨 著 計 算 機 和 網 絡 技 術 的 發 展, 很 多 數 據 處 理 系 統 都 采 用 開 放 系 統 結 構 的 客 戶 機/ 服 務 器 網 絡 模 式。 即 客 戶 機 提 出 任 務 請 求, 由 服 務 器 做 相 應 處 理, 執 行 被 請 求 的 任 務, 然 后 將 結 果 返 回 給 客 戶 機。 例 如: 銀 行ATM 的 前 置 機 和 數 據 處 理 的 主 機 之 間 即 構 成 客 戶 機/ 服 務 器 模 式; 電 話 銀 行 的 前 置 機 和 銀 行 數 據 處 理 主 機 之 間 也 構 成 這 種 模 式 結 構。 還 有POS 等。 這 樣, 各 種 應 用 的 請 求 是 很 頻 繁 的, 數 據 主 機 在 處 理 通 存 通 兌, ATM, 電 話 銀 行, POS 等 各 種 請 求 時, 如 果 沒 有 相 應 機 制 的 控 制, 數 據 將 出 現 混 亂, 有 可 能 產 生 透 支, 也 有 可 能 處 理 密 碼 已 改 變 的 帳 戶.。 數 據 的 完 整 性, 安 全 性 無 法 控 制。 而 消 息 隊 列 正 是 解 決 這 一 問 題 的 有 力 工 具。 它 使 主 機 在 處 理 各 種 請 求 時, 按 照 先 后 順 序 有 條 不 紊 地 進 行, 保 證 了 數 據 的 一 致 性 和 安 全 性。

          二、 基 本 概 念

          ---- 1. 隊 列

          ---- 隊 列 是 信 息 的 線 性 表, 它 的 訪 問 次 序 是 先 進 先 出(FIFO)。 也 就 是 說, 置 入 隊 列 中 的 第 一 個 數 據 項 將 是 從 隊 列 中 第 一 次 讀 出 的 數 據 項, 置 入 的 第 二 項 將 是 讀 出 的 第 二 項, 依 此 類 推。 這 是 隊 列 允 許 的 唯 一 存 取 操 作, 其 它 隨 機 訪 問 是 不 允 許 的。 這 種 數 據 結 構 保 證 對 數 據 資 源 的 請 求 將 嚴 格 按 照 先 后 順 序 進 行, 因 而 可 用 于 對 事 件 的 調 度 并 起 到I/O 緩 沖 的 作 用。

          ---- 2. 報 文

          ---- 發 送 進 程 和 接 收 進 程 進 行 信 息 的 交 換, 一 般 是 通 過 將 信 息 劃 分 為 若 干 段 放 入 數 據 交 換 緩 沖 器 中, 進 程 間 通 過 對 該 緩 沖 器 的 存 取 來 實 現 通 信。 因 此, 數 據 是 以 不 連 續 的 形 式 在 進 程 間 傳 送, 這 些 不 連 續 的 部 分 就 叫 報 文。

          ---- 3. 消 息 隊 列

          ---- 將 報 文 按 隊 列 的 結 構 進 行 組 織 就 叫 消 息 隊 列。 該 隊 列 用 于 存 放 正 被 發 送 或 接 收 的 每 一 個 報 文 的 標 題 信 息。 每 一 個 消 息 隊 列 還 對 應 有 一 個 數 據 結 構, 它 含 有 消 息 隊 列 的 存 取 權 限, 和 消 息 隊 列 的 當 前 狀 態 信 息 等 信 息。 消 息 隊 列 可 進 行" 發 送" 和" 接 收" 操 作。

          三、 消 息 隊 列 的 編 程 要 點 及 運 作 過 程

          ---- 1. 消 息 隊 列 的 創 建

          ---- 在 報 文 能 夠 發 送 和 接 收 之 前, 必 須 創 建 一 個 能 夠 唯 一 被 識 別 出 的 消 息 隊 列 和 數 據 結 構, 這 個 被 創 建 的 唯 一 標 識 符 叫 做 消 息 隊 列 描 述 符(msqid), 用 來 識 別 或 引 用 相 關 的 消 息 隊 列 和 數 據 結 構。 用msgget(long key, int msgflg) 系 統 調 用 來 創 建 消 息 隊 列, 其 中 key 是 一 個 長 整 型, 可 由 用 戶 設 定 也 可 通 過ftok() 獲 得。msgflg 的 值 是 八 進 制 的 消 息 隊 列 操 作 權 和 控 制 命 令 的 組 合。 操 作 權 定 義 為:

          操作允許權 八進制整數

          用戶可讀 0400

          用戶可寫 0200

          同組可讀 0040

          同組可寫 0020

          其它可讀 0004

          其它可寫 0002


          ---- 操 作 權 可 相 加 而 派 生, 如 用 戶 可" 讀"、" 寫" 的 權 限 為0400|0200=0600。 控 制 命 令 可 取IPC_CREAT 或IPC_EXCL。 如 果 要 創 建 一 個key=888 且 屬 主 和 同 組 可 讀 寫 的 消 息 隊 列, 執 行 以 下 系 統 調 用msgget(0x888,0660|IPC_CREAT)。 創 建 后 可 用ipcs 命 令 看 到 以 下 信 息:


          IPC status from /dev/mem as of Sun

          Jan 25 06:49:52 1970

          T ID KEY MODE OWNER GROUP

          Message Queues:

          . q 7 0x00000888 --rw-rw----

          root system

          ...


          ---- 它 的 消 息 隊 列 描 述 符 是7, 屬 主 是root , 同 組 是system, 存 取 權 是 屬 主、 用 戶 可 讀 寫。 如 果 執 行msgget(0x888,0660|IPC_CREAT) 時, 與0x888 對 應 的 消 息 隊 列 已 存 在, 則 返 回 該 消 息 隊 列 的 描 述 符msqid。
          ---- 2. 消 息 的 發 送

          ---- 消 息 隊 列 一 經 創 建 即 可 用msgsnd(int msqid, void *msgp, size_t msgsz, int msgflg) 發 送 消 息。msgqid 是 經msgget 創 建 的 消 息 隊 列 描 述 符,msgp 是 指 向 消 息 段 的 指 針, 該 指 針 所 指 結 構 含 有 報 文 類 型 和 要 發 送 或 接 收 的 報 文:

          struct msgbuf {

          long mtype;/*消息類型*/

          char mtext[512];

          /* 消息正文,512暫定為消息段的大小*/

          }

          ---- msgsz 是msgp 參 量 指 向 的 數 據 結 構 中 字 符 數 組 的 長 度, 即 報 文 長 度, 最 大 值 由MSGMAX 確 定。msgflg 是 當 消 息 隊 列 滿 時( 隊 列 中 無 空 閑 空 間), 系 統 要 采 取 的 行 動. 如 果msgflg&IPC_NOWAIT= 真, 調 用 進 程 立 即 返 回, 不 發 送 該 消 息。 如 果msgflg&IPC_NOWAIT= 假, 調 用 進 程 暫 停 執 行, 處 于" 掛 起" 狀 態, 且 不 發 送 該 消 息。 直 到 下 列 情 況 之 一 出 現:
          ---- - 引 起 暫 停 的 條 件 不 再 存 在, 如 隊 列 出 現 空 閑, 即 可 發 送
          ---- - 該 消 系 隊 列 被 從 系 統 中 刪 去
          ---- - 調 用 進 程 接 收 到 一 個 要 捕 捉 的 信 號, 如 中 斷 信 號, 此 時 不 發 送 消 息, 調 用 進 程 按signal 中 描 述 的 方 式 執 行。

          ---- 如 果msgsnd 返 回0 則 發 送 成 功。 返 回-1 則 表 示 發 送 失 敗, 錯 誤 類 型 可 具 體 查 看errno。

          ---- 3. 消 息 的 接 收

          ---- 用 msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) 系 統 調 用 從 msqid 消 息 隊 列 中 讀 取 一 條 信 息 并 將 其 放 入 消 息 段 指 針msgp 指 向 的 結 構。msgsz 給 出mtext 的 字 節 數, 如 果 所 接 收 的 消 息 比msgsz 大 且msgflg&MSG_NOERROR 為 真, 則 按msgsz 的 大 小 截 斷 而 不 通 知 調 用 進 程。msgtyp 指 定 要 求 的 消 息 類 型:

          ---- msgtyp=0 接 收 消 息 隊 列 中 的 第 一 個 報 文
          ---- msgtyp >0 接 收 消 息 隊 列 中 的 類 型 為msgtyp 的 第 一 個 報 文
          ---- msgtyp< 0 接 收 消 息 隊 列 中 小 于 等 于msgtyp 絕 對 值 的 最 低 類 型 的 第 一 個 報 文

          ---- 當 隊 列 上 沒 有 所 期 望 類 型 的 消 息 或 消 息 隊 列 為 空 時msgflg 指 出 調 用 進 程 要 采 取 的 行 動: 如 果msgflg&IPC_NOWAIT 為 真, 則 調 用 進 程 立 即 結 束 并 返 回-1。 如msgflg&IPC_NOWAIT 為 假, 則 調 用 進 程 暫 停 執 行 直 至 出 現:

          ---- - 隊 列 中 放 入 所 需 類 型 的 消 息, 調 用 進 程 接 收 該 消 息
          ---- -msqid 消 息 隊 列 從 系 統 中 刪 除
          ---- - 調 用 進 程 接 收 到 捕 獲 的 信 號, 此 時 不 接 收 消 息, 調 用 進 程 按signal 描 述 的 方 式 執 行。

          ---- 如 果msgrev 執 行 成 功, 則 返 回 放 入mtext 中 的 字 節 數, 失 敗 返 回-1 , 錯 誤 類 型 可 查errno。

          ---- 4. 消 息 隊 列 的 控 制 和 撤 銷

          ---- 用 msgctl(int msqid, int cmd, struct msqid_ds *buf) 系 統 調 用 實 現 對 消 息 隊 列 的 控 制。msgqid 必 須 是 用msgget 創 建 的 消 息 隊 列 描 述 符。cmd 可 以 是:

          ---- IPC_STAT 查 看 消 息 隊 列 的 狀 態, 結 果 放 入buf 指 針 指 向 的 結 構
          ---- IPC_SET 為 消 息 隊 列 設 置 屬 主 標 識, 同 組 標 識, 操 作 允 許 權, 最 大 字 節 數
          ---- IPC_RMID 刪 除 指 定 的msqid 以 及 相 關 的 消 息 隊 列 和 結 構

          四、 編 程 示 例

          ---- 下 面 給 出 一 個 運 用 消 息 隊 列, 實 現 進 程 通 信 的 實 例。 以 下 程 序 在 IBM RS/6000 小 型 機(AIX 操 作 系 統) 上 和IBM PC(UNIX 操 作 系 統) 上 分 別 調 試 通 過。 該 程 序 主 要 模 擬 根 據 帳 號 查 詢 余 額 的 過 程。 包 括 三 方 面:

          請 求 進 程 從 標 準 輸 入 讀 入 帳 號, 并 將 該 帳 號 通 過 消 息 隊 列 發 送 給 服 務 進 程;

          服 務 進 程 接 收 該 帳 號 后, 按 照 請 求 的 先 后 順 序 在 標 準 輸 入 上 輸 入 該 帳 戶 的 姓 名 和 余 額, 并 將 結 果 返 回 給 客 戶 進 程;

          請 求 進 程 接 收 返 回 的 信 息, 并 將 結 果 輸 出 在 標 準 輸 出 上。
          ---- 服 務 進 程(msgcenter) 先 于 請 求 進 程(msgreq) 啟 動. 客 戶 進 程 啟 動 時 要 攜 帶 請 求 編 號, 可 同 時 起 動 多 個 請 求 進 程。


          /*請求方程序msgreq.c*/

          #include

          #include

          #include

          #include

          #include

          static struct msgbuf1{

          long mtype;

          char mtext[100];

          } sndbuf, rcvbuf, *msgp ;

          extern int errno;

          main(int argc, char **argv)

          { int rtrn, msqid ;

          char name[10];

          double balance;

          if (argc!=2){ fprintf(stderr,

          "msgreq [01-99]\n"); exit(-1); }

          if ( (msqid = msgget(0x888, IPC_CREAT|0660)) == -1 ){

          fprintf(stderr, "msgget 888 failed !\n"); exit(-1);

          }

          msgp=&sndbuf;

          sprintf(sndbuf.mtext,"%2.2s",argv[1]);

          printf("輸入4位帳號:");

          scanf("%s",&sndbuf.mtext[2]);

          sndbuf.mtext[6]=0;

          msgp->mtype=666;

          rtrn=msgsnd(msqid,msgp, strlen(sndbuf.mtext), 0);

          if (rtrn==-1){

          perror("msgsnd"); exit(-1);

          }

          msgp=&rcvbuf;

          fprintf(stderr,"等待后臺數據處理進程的回答....");

          rtrn=msgrcv(msqid,msgp, 100, atoi(argv[1]), 0);

          if(rtrn==-1){ perror("msgrcv"); exit(-1); }

          sscanf(rcvbuf.mtext,"%[^|]|%lf",name,&balance);

          printf("\n姓名=%s\n",name);

          printf("余額=%lf\n",balance);

          }

          /*服務方程序msgcenter.c*/

          #include

          #include

          #include

          #include

          #include

          static struct msgbuf1{

          long mtype;

          char mtext[100];

          } sndbuf, rcvbuf , *msgp;

          extern int errno;

          main()

          { int rtrn, msgqid ;

          char strbuf[100];

          if ( (msqid = msgget(0x888, IPC_CREAT|0600)) == -1 ){

          fprintf(stderr, "msgget 888 failed !\n"); exit(-1);

          }

          while(1) {

          msgp=&rcvbuf;

          fprintf(stderr,"等待前臺進程的請求....");

          rtrn=msgrcv(msqid, msgp, 100, 666 ,MSG_NOERROR);

          if(rtrn==-1){ perror("msgrcv");exit(-1); }

          msgp=&sndbuf;

          sprintf(strbuf,"%2.2s\0",rcvbuf.mtext);

          msgp->mtype=atoi(strbuf);

          printf("\n輸入帳號=%4.4s的帳戶姓名:",&rcvbuf.mtext[2]);

          scanf("%s",sndbuf.mtext);

          strcat(sndbuf.mtext,"|");

          printf("輸入該帳戶余額:");

          scanf("%s",strbuf);

          strcat(sndbuf.mtext,strbuf);

          rtrn=msgsnd(msqid,msgp, strlen(sndbuf.mtext), 0);

          if (rtrn==-1){ perror("msgsnd"); exit(-1); }

          }

          }

          轉自:http://fanqiang.chinaunix.net/program/other/2001-07-06/2147.shtml

          posted on 2005-08-04 12:55 weidagang2046 閱讀(678) 評論(0)  編輯  收藏 所屬分類: Linux

          主站蜘蛛池模板: 民县| 开封市| 昌乐县| 高要市| 乳山市| 宁蒗| 宁国市| 长治市| 德州市| 石楼县| 临颍县| 历史| 丹东市| 芜湖市| 伊川县| 淮南市| 鄂尔多斯市| 武陟县| 崇阳县| 南阳市| 互助| 潼关县| 宁远县| 湖北省| 东乡| 洪雅县| 呼伦贝尔市| 榆中县| 巩义市| 柞水县| 文安县| 墨竹工卡县| 卢氏县| 洪洞县| 原阳县| 西安市| 彰化市| 龙江县| 金湖县| 治县。| 林州市|