大家好,我是ST。
今天主要聊一聊,如何使用Linux系統(tǒng)下的msg實現(xiàn)銀行終端系統(tǒng)的模擬及運行。
第一:msg基本簡介
????Linux系統(tǒng)中IPC通信有多種方式,msg是其中的一種通信方式,稱為消息隊列。Linux系統(tǒng)中可以通過ipcs -q來查看所有存在的消息隊列。
????消息隊列與FIFO很類似,都是一個隊列結構,并可以實現(xiàn)多進程往隊列寫入信息,以及多進程可以從隊列里面讀取信息。但是FIFO需要讀寫兩個端口,事先要打開,這樣才能正常傳遞消息。而消息隊列可以事先往隊列里面寫入消息,或者需要時候再打開,讀取消息。
?????注意:消息隊列提供了一個從一個進程往另外一個進程發(fā)送數(shù)據(jù)塊的方法,并且每個數(shù)據(jù)塊可以包含多個數(shù)據(jù)類型,接收的進程可以獨立接收不同的數(shù)據(jù)類型。
第二:Linux內核中msg相關的API函數(shù)
#include
?第三:銀行終端系統(tǒng)的實現(xiàn)原理
補充項:服務器開啟時負責創(chuàng)建兩個消息隊列,退出時銷毀所有子進程以及兩個消息隊列。
第四:銀行終端系統(tǒng)的實現(xiàn)步驟
?一、程序設計思路
分為兩個模塊:1.服務器 2.客戶端
1.服務器要做的工作就是,在運行服務器的時候讓服務器去啟動各個進程,開戶,存款,查詢,銷戶...,可以使用vfork+execl去實現(xiàn),(要保證服務器一直在運行不能讓服務器退出),由于服務器要啟動每一個進程所以采用for循環(huán)語句可以定義一個結構體去填寫每一個需要啟動的進程的路徑以及名字execl()函數(shù)啟動。服務器退出的時候要殺死每一個進程以及刪除消息隊列。
2.客戶端主要實現(xiàn)各個函數(shù)功能的調用菜單的編寫,采用模塊化編程的方式去寫代碼,每一個模塊分別編寫一個.c文件這樣方便調試和管理,進程之間的通信采用消息隊列的方式通信,每一個進程所發(fā)的消息可以采用消息隊列結構體中的消息類型來區(qū)分,將每一個用戶的信息都保存成一個文件,方便后期的信息查詢,(如果有同學學了數(shù)據(jù)庫可以將每一位用戶的信息都保存到數(shù)據(jù)中)用戶在開戶的時候,賬號如果不想采用順序分配(本次系統(tǒng)采用的是順序分配),也可以采用srand((unsigned int)time(NULL))+rand()去進行隨機分配。
二、流程圖設計
三、編寫代碼
?
//服務器 static int g_reqid = -1;//請求消息隊列 static int g_resid = -1;//響應消息隊列 typedef struct tag_Service { ? ? char ?srv_path[PATH_MAX+1]; ? ? pid_t srv_pid; } ? SERVICE; static SERVICE g_srv[] = { ? ? {"./open", ? ? -1}, ? ? {"./close", ? ?-1}, ? ? {"./save", ? ? -1}, ? ? {"./withdraw", -1}, ? ? {"./query", ? ?-1}, ? ? {"./transfer", -1} }; int init (void) { ? ? printf ("服務器初始化... "); ? ? //創(chuàng)建請求消息隊列 ? ? if ((g_reqid = msgget (KEY_REQUEST, ? ? ? ? 0600 | IPC_CREAT | IPC_EXCL)) == -1) { ? ? ? ? perror ("msgget"); ? ? ? ? return -1; ? ? } ? ? printf ("創(chuàng)建請求消息隊列成功! "); ? ? //創(chuàng)建響應消息隊列 ? ? if ((g_resid = msgget (KEY_RESPOND, ? ? ? ? 0600 | IPC_CREAT | IPC_EXCL)) == -1) { ? ? ? ? perror ("msgget"); ? ? ? ? return -1; ? ? } ? ? printf ("創(chuàng)建響應消息隊列成功! "); ? ? return 0; } void deinit (void) { ? ? printf ("服務器終結化... "); ? ? if (msgctl (g_reqid, IPC_RMID, NULL) == -1) ? ? ? ? perror ("msgctl"); ? ? else ? ? ? ? printf ("銷毀請求消息隊列成功! "); ? ? if (msgctl (g_resid, IPC_RMID, NULL) == -1) ? ? ? ? perror ("msgctl"); ? ? else ? ? ? ? printf ("銷毀響應消息隊列成功! "); } int start (void) { ? ? printf ("啟動業(yè)務服務... "); ? ? size_t i; ? ? //利用for循環(huán)的去vfork幾個子進程 ? ? for (i = 0; i < sizeof (g_srv) / sizeof (g_srv[0]); i++) { ? ? ? ? if ((g_srv[i].srv_pid = vfork ()) == -1) { ? ? ? ? ? ? perror ("vfork"); ? ? ? ? ? ? return -1; ? ? ? ? } ? ? ? ? //調用execl函數(shù)去循環(huán)的啟動每一個可執(zhí)行的進程 ? ? ? ? if (g_srv[i].srv_pid == 0) { ? ? ? ? ? ? if (execl (g_srv[i].srv_path, g_srv[i].srv_path, ? ? ? ? ? ? ? ? NULL) == -1) { ? ? ? ? ? ? ? ? perror ("execl"); ? ? ? ? ? ? ? ? return -1; ? ? ? ? ? ? } ? ? ? ? ? ? return 0; ? ? ? ? } ? ? } ? ? return 0; } int stop (void) { ? ? printf ("停止業(yè)務服務... "); ? ? size_t i; ? ? for (i = 0; i < sizeof (g_srv) / sizeof (g_srv[0]); i++) ? ? ? ? if (kill (g_srv[i].srv_pid, SIGINT) == -1) { ? ? ? ? ? ? perror ("kill"); ? ? ? ? ? ? return -1; ? ? ? ? } ? ? for (;;) ? ? ? ? if (wait (0) == -1) { ? ? ? ? ? ? if (errno != ECHILD) { ? ? ? ? ? ? ? ? perror ("wait"); ? ? ? ? ? ? ? ? return -1; ? ? ? ? ? ? } ? ? ? ? ? ? break; ? ? ? ? } ? ? return 0; } void sigint(int signum) { ? ? printf("%d ", signum);//打印出信號量的數(shù)值(2) ? ? stop();//調用此函數(shù) ? ? exit(0); } int main (void) { ? ? atexit (deinit);// 注冊終止函數(shù)(即main執(zhí)行結束后調用的函數(shù)) ? ? ? ? signal(SIGINT, sigint);//產(chǎn)生ctrl+c信號的時候就去執(zhí)行sigint函數(shù) ? ? if (init () == -1) ? ? ? ? return -1; ? ? if (start () == -1) ? ? ? ? return -1; ? ? sleep (1); ? ? printf ("按<回車>退出... "); ? ? getchar (); ? ? if (stop () == -1) ? ? ? ? return -1; ? ? return 0; }
//頭文件bank.h #ifndef _BANK_H #define _BANK_H #include#include #define KEY_REQUEST 0x12345678 #define KEY_RESPOND 0x87654321 #define TYPE_OPEN 8001 #define TYPE_CLOSE 8002 #define TYPE_SAVE 8003 #define TYPE_WITHDRAW 8004 #define TYPE_QUERY 8005 #define TYPE_TRANSFER 8006 //賬戶 typedef struct tag_Account { int id;//ID號 char name[256];//用戶名 char passwd[9];//密碼 double balance;//金額 } ACCOUNT; //開戶時的結構體 typedef struct tag_OpenRequest { long type;//類型 pid_t pid; char name[256]; char passwd[9]; double balance; } OPEN_REQUEST; //開戶應答結構體 typedef struct tag_OpenRespond { long type; char error[512]; int id; } OPEN_RESPOND; //清戶結構體 typedef struct tag_CloseRequest { long type; pid_t pid; int id; char name[256]; char passwd[9]; } CLOSE_REQUEST; //清戶應答結構體 typedef struct tag_CloseRespond { long type; char error[512]; double balance; } CLOSE_RESPOND; //存款結構體 typedef struct tag_SaveRequest { long type; pid_t pid; int id; char name[256]; double money; } SAVE_REQUEST; //存款應答結構體 typedef struct tag_SaveRespond { long type; char error[512]; double balance; } SAVE_RESPOND; //取款結構體 typedef struct tag_WithdrawRequest { long type; pid_t pid; int id; char name[256]; char passwd[9]; double money; } WITHDRAW_REQUEST; //取款應答結構體 typedef struct tag_WithdrawRespond { long type; char error[512]; double balance; } WITHDRAW_RESPOND; //查詢結構體 typedef struct tag_QueryRequest { long type; pid_t pid; int id; char name[256]; char passwd[9]; } QUERY_REQUEST; //查詢應答結構體 typedef struct tag_QueryRespond { long type; char error[512]; double balance; } QUERY_RESPOND; //轉賬結構體 typedef struct tag_TransferRequest { long type; pid_t pid; int id[2]; char name[2][256]; char passwd[9]; double money; } TRANSFER_REQUEST; //轉賬應答結構體 typedef struct tag_TransferRespond { long type; char error[512]; double balance; } TRANSFER_RESPOND; #endif // _BANK_H
static int g_reqid = -1; static int g_resid = -1; void menu_loop (int (*menu) (void), int (*on_menu[]) (void), ? ? size_t size) { ? ? for (;;) { ? ? ? ? int id = menu (); ? ? ? ? if (id < 0 || size <= id) ? ? ? ? ? ? printf ("無效選擇! "); ? ? ? ? else if (on_menu[id] () == -1) ? ? ? ? ? ? break; ? ? } } int main_menu (void) { ? ? printf ("-------- "); ? ? printf ("本地銀行 "); ? ? printf ("-------- "); ? ? printf ("[1] 開戶 "); ? ? printf ("[2] 清戶 "); ? ? printf ("[3] 存款 "); ? ? printf ("[4] 取款 "); ? ? printf ("[5] 查詢 "); ? ? printf ("[6] 轉賬 "); ? ? printf ("[0] 退出 "); ? ? printf ("-------- "); ? ? printf ("請選擇:"); ? ? int id = -1; ? ? scanf ("%d", &id); ? ? scanf ("%*[^ ]"); ? ? scanf ("%*c"); ? ? return id; } //0 退出 int on_quit (void) { ? ? printf ("謝謝使用,再見! "); ? ? return -1; } //1 開戶 int on_open (void) { ? ? pid_t pid = getpid ();//獲得該進程號 ? ? OPEN_REQUEST req = {TYPE_OPEN, pid};//TYPE_OPEN 8001 ? ? printf ("戶名:"); ? ? scanf ("%s", req.name); ? ? printf ("密碼:"); ? ? scanf ("%s", req.passwd); ? ? printf ("金額:"); ? ? scanf ("%lf", &req.balance); ? ? //把消息添加到已打開的請求消息隊列末尾 ? ? if (msgsnd (g_reqid, &req, sizeof (req) - sizeof (req.type), ? ? ? ? 0) == -1) { ? ? ? ? perror ("msgsnd"); ? ? ? ? return 0; ? ? } ? ? OPEN_RESPOND res;//定義一個應答結構體變量 ? ? //把消息從響應消息隊列中取走 ? ? if (msgrcv (g_resid, &res, sizeof (res) - sizeof (res.type), ? ? ? ? pid, 0) == -1) { ? ? ? ? perror ("msgrcv"); ? ? ? ? return 0; ? ? } ? ? if (strlen (res.error)) { ? ? ? ? printf ("%s ", res.error); ? ? ? ? return 0; ? ? } ? ? printf ("賬號:%d ", res.id); ? ? return 0; } //2 清戶 int on_close (void) { ? ? pid_t pid = getpid (); ? ? CLOSE_REQUEST req = {TYPE_CLOSE, pid}; ? ? printf ("賬號:"); ? ? scanf ("%d", &req.id); ? ? printf ("戶名:"); ? ? scanf ("%s", req.name); ? ? printf ("密碼:"); ? ? scanf ("%s", req.passwd); ? ? if (msgsnd (g_reqid, &req, sizeof (req) - sizeof (req.type), ? ? ? ? 0) == -1) { ? ? ? ? perror ("msgsnd"); ? ? ? ? return 0; ? ? } ? ? CLOSE_RESPOND res; ? ? if (msgrcv (g_resid, &res, sizeof (res) - sizeof (res.type), ? ? ? ? pid, 0) == -1) { ? ? ? ? perror ("msgrcv"); ? ? ? ? return 0; ? ? } ? ? if (strlen (res.error)) { ? ? ? ? printf ("%s ", res.error); ? ? ? ? return 0; ? ? } ? ? printf ("余額:%.2lf ", res.balance); ? ? return 0; } //3 存款 int on_save (void) { ? ? pid_t pid = getpid (); ? ? SAVE_REQUEST req = {TYPE_SAVE, pid}; ? ? printf ("賬號:"); ? ? scanf ("%d", &req.id); ? ? printf ("戶名:"); ? ? scanf ("%s", req.name); ? ? printf ("金額:"); ? ? scanf ("%lf", &req.money); ? ? if (msgsnd (g_reqid, &req, sizeof (req) - sizeof (req.type), ? ? ? ? 0) == -1) { ? ? ? ? perror ("msgsnd"); ? ? ? ? return 0; ? ? } ? ? SAVE_RESPOND res; ? ? if (msgrcv (g_resid, &res, sizeof (res) - sizeof (res.type), ? ? ? ? pid, 0) == -1) { ? ? ? ? perror ("msgrcv"); ? ? ? ? return 0; ? ? } ? ? if (strlen (res.error)) { ? ? ? ? printf ("%s ", res.error); ? ? ? ? return 0; ? ? } ? ? printf ("余額:%.2lf ", res.balance); ? ? return 0; } //4?取款 int on_withdraw (void) { ? ? pid_t pid = getpid (); ? ? WITHDRAW_REQUEST req = {TYPE_WITHDRAW, pid}; ? ? printf ("賬號:"); ? ? scanf ("%d", &req.id); ? ? printf ("戶名:"); ? ? scanf ("%s", req.name); ? ? printf ("密碼:"); ? ? scanf ("%s", req.passwd); ? ? printf ("金額:"); ? ? scanf ("%lf", &req.money); ? ? if (msgsnd (g_reqid, &req, sizeof (req) - sizeof (req.type), ? ? ? ? 0) == -1) { ? ? ? ? perror ("msgsnd"); ? ? ? ? return 0; ? ? } ? ? WITHDRAW_RESPOND res; ? ? if (msgrcv (g_resid, &res, sizeof (res) - sizeof (res.type), ? ? ? ? pid, 0) == -1) { ? ? ? ? perror ("msgrcv"); ? ? ? ? return 0; ? ? } ? ? if (strlen (res.error)) { ? ? ? ? printf ("%s ", res.error); ? ? ? ? return 0; ? ? } ? ? printf ("余額:%.2lf ", res.balance); ? ? return 0; } //5 查詢 int on_query (void) { ? ? pid_t pid = getpid (); ? ? QUERY_REQUEST req = {TYPE_QUERY, pid}; ? ? printf ("賬號:"); ? ? scanf ("%d", &req.id); ? ? printf ("戶名:"); ? ? scanf ("%s", req.name); ? ? printf ("密碼:"); ? ? scanf ("%s", req.passwd); ? ? if (msgsnd (g_reqid, &req, sizeof (req) - sizeof (req.type), ? ? ? ? 0) == -1) { ? ? ? ? perror ("msgsnd"); ? ? ? ? return 0; ? ? } ? ? QUERY_RESPOND res; ? ? if (msgrcv (g_resid, &res, sizeof (res) - sizeof (res.type), ? ? ? ? pid, 0) == -1) { ? ? ? ? perror ("msgrcv"); ? ? ? ? return 0; ? ? } ? ? if (strlen (res.error)) { ? ? ? ? printf ("%s ", res.error); ? ? ? ? return 0; ? ? } ? ? printf ("余額:%.2lf ", res.balance); ? ? return 0; } //6 轉賬 int on_transfer (void) { ? ? pid_t pid = getpid (); ? ? TRANSFER_REQUEST req = {TYPE_TRANSFER, pid}; ? ? printf ("賬號:"); ? ? scanf ("%d", &req.id[0]); ? ? printf ("戶名:"); ? ? scanf ("%s", req.name[0]); ? ? printf ("密碼:"); ? ? scanf ("%s", req.passwd); ? ? printf ("金額:"); ? ? scanf ("%lf", &req.money); ? ? printf ("對方賬號:"); ? ? scanf ("%d", &req.id[1]); ? ? printf ("對方戶名:"); ? ? scanf ("%s", req.name[1]); ? ? if (msgsnd (g_reqid, &req, sizeof (req) - sizeof (req.type), ? ? ? ? 0) == -1) { ? ? ? ? perror ("msgsnd"); ? ? ? ? return 0; ? ? } ? ? TRANSFER_RESPOND res; ? ? if (msgrcv (g_resid, &res, sizeof (res) - sizeof (res.type), ? ? ? ? pid, 0) == -1) { ? ? ? ? perror ("msgrcv"); ? ? ? ? return 0; ? ? } ? ? if (strlen (res.error)) { ? ? ? ? printf ("%s ", res.error); ? ? ? ? return 0; ? ? } ? ? printf ("余額:%.2lf ", res.balance); ? ? return 0; } int main (void) { ? ? if ((g_reqid = msgget (KEY_REQUEST, 0)) == -1) {//發(fā)送請求消息隊列 ? ? ? ? perror ("msgget"); ? ? ? ? return -1; ? ? } ? ? if ((g_resid = msgget (KEY_RESPOND, 0)) == -1) {//獲得響應消息隊列 ? ? ? ? perror ("msgget"); ? ? ? ? return -1; ? ? } //定義函數(shù)指針數(shù)組 ? ? int (*on_menu[]) (void) = {on_quit, on_open, on_close, ? ? ? ? on_save, on_withdraw, on_query, on_transfer}; ? ? menu_loop (main_menu, on_menu, ? ? ? ? sizeof (on_menu) / sizeof (on_menu[0])); ? ? return 0; }
//開戶子進程(open.c) void sigint (int signum) { ? ? printf ("開戶服務:即將停止。 "); ? ? exit (0); } int main (void) { ? ? if (signal (SIGINT, sigint) == SIG_ERR) {//產(chǎn)生ctrl+c信號的時候就去執(zhí)行sigint函數(shù) ? ? ? ? perror ("signal"); ? ? ? ? return -1; ? ? } ? ? //獲得消息隊列 ? ? int reqid = msgget (KEY_REQUEST, 0); ? ? if (reqid == -1) { ? ? ? ? perror ("msgget"); ? ? ? ? return -1; ? ? } ? ? //獲得相應消息隊列 ? ? int resid = msgget (KEY_RESPOND, 0); ? ? if (resid == -1) { ? ? ? ? perror ("msgget"); ? ? ? ? return -1; ? ? } ? ? printf ("開戶服務:啟動就緒。 "); ? ? for (;;) { ? ? ? ? OPEN_REQUEST req; ? ? ? ? if (msgrcv (reqid, &req, sizeof (req) - sizeof (req.type), ? ? ? ? ? ? TYPE_OPEN, 0) == -1) { ? ? ? ? ? ? perror ("msgrcv"); ? ? ? ? ? ? continue; ? ? ? ? } ? ? ? ? OPEN_RESPOND res = {req.pid, ""}; ? ? ? ? ACCOUNT acc; ? ? ? ? if ((acc.id = genid ()) == -1) { ? ? ? ? ? ? sprintf (res.error, "創(chuàng)立賬戶失??!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? strcpy (acc.name, req.name); ? ? ? ? strcpy (acc.passwd, req.passwd); ? ? ? ? acc.balance = req.balance; ? ? ? ? if (save (&acc) == -1) { ? ? ? ? ? ? sprintf (res.error, "保存賬戶失?。?); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? res.id = acc.id; send_respond: ? ? ? ? if (msgsnd (resid, &res, sizeof (res) - sizeof (res.type), ? ? ? ? ? ? 0) == -1) { ? ? ? ? ? ? perror ("msgsnd"); ? ? ? ? ? ? continue; ? ? ? ? } ? ? } ? ? return 0; }
//銷戶子進程(close.c) void sigint (int signum) { ? ? printf ("清戶服務:即將停止。 "); ? ? exit (0); } int main (void) { ? ? if (signal (SIGINT, sigint) == SIG_ERR) { ? ? ? ? perror ("signal"); ? ? ? ? return -1; ? ? } ? ? int reqid = msgget (KEY_REQUEST, 0); ? ? if (reqid == -1) { ? ? ? ? perror ("msgget"); ? ? ? ? return -1; ? ? } ? ? int resid = msgget (KEY_RESPOND, 0); ? ? if (resid == -1) { ? ? ? ? perror ("msgget"); ? ? ? ? return -1; ? ? } ? ? printf ("清戶服務:啟動就緒。 "); ? ? for (;;) { ? ? ? ? CLOSE_REQUEST req; ? ? ? ? if (msgrcv (reqid, &req, sizeof (req) - sizeof (req.type), ? ? ? ? ? ? TYPE_CLOSE, 0) == -1) { ? ? ? ? ? ? perror ("msgrcv"); ? ? ? ? ? ? continue; ? ? ? ? } ? ? ? ? CLOSE_RESPOND res = {req.pid, ""}; ? ? ? ? ACCOUNT acc; ? ? ? ? if (get (req.id, &acc) == -1) { ? ? ? ? ? ? sprintf (res.error, "無效賬號!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? if (strcmp (req.name, acc.name)) { ? ? ? ? ? ? sprintf (res.error, "無效戶名!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? if (strcmp (req.passwd, acc.passwd)) { ? ? ? ? ? ? sprintf (res.error, "密碼錯誤!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? if (delete (req.id) == -1) { ? ? ? ? ? ? sprintf (res.error, "刪除賬戶失?。?); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? res.balance = acc.balance; send_respond: ? ? ? ? if (msgsnd (resid, &res, sizeof (res) - sizeof (res.type), ? ? ? ? ? ? 0) == -1) { ? ? ? ? ? ? perror ("msgsnd"); ? ? ? ? ? ? continue; ? ? ? ? } ? ? } ? ? return 0; }
//存款子進程(save.c) void sigint (int signum) { ? ? printf ("清戶服務:即將停止。 "); ? ? exit (0); } int main (void) { ? ? if (signal (SIGINT, sigint) == SIG_ERR) { ? ? ? ? perror ("signal"); ? ? ? ? return -1; ? ? } ? ? int reqid = msgget (KEY_REQUEST, 0); ? ? if (reqid == -1) { ? ? ? ? perror ("msgget"); ? ? ? ? return -1; ? ? } ? ? int resid = msgget (KEY_RESPOND, 0); ? ? if (resid == -1) { ? ? ? ? perror ("msgget"); ? ? ? ? return -1; ? ? } ? ? printf ("清戶服務:啟動就緒。 "); ? ? for (;;) { ? ? ? ? CLOSE_REQUEST req; ? ? ? ? if (msgrcv (reqid, &req, sizeof (req) - sizeof (req.type), ? ? ? ? ? ? TYPE_CLOSE, 0) == -1) { ? ? ? ? ? ? perror ("msgrcv"); ? ? ? ? ? ? continue; ? ? ? ? } ? ? ? ? CLOSE_RESPOND res = {req.pid, ""}; ? ? ? ? ACCOUNT acc; ? ? ? ? if (get (req.id, &acc) == -1) { ? ? ? ? ? ? sprintf (res.error, "無效賬號!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? if (strcmp (req.name, acc.name)) { ? ? ? ? ? ? sprintf (res.error, "無效戶名!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? if (strcmp (req.passwd, acc.passwd)) { ? ? ? ? ? ? sprintf (res.error, "密碼錯誤!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? if (delete (req.id) == -1) { ? ? ? ? ? ? sprintf (res.error, "刪除賬戶失敗!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? res.balance = acc.balance; send_respond: ? ? ? ? if (msgsnd (resid, &res, sizeof (res) - sizeof (res.type), ? ? ? ? ? ? 0) == -1) { ? ? ? ? ? ? perror ("msgsnd"); ? ? ? ? ? ? continue; ? ? ? ? } ? ? } ? ? return 0; }
//取款子進程(withdraw.c) void?sigint?(int?signum)?{ ? ? printf ("取款服務:即將停止。 "); ? ? exit (0); } int main (void) { ? ? if (signal (SIGINT, sigint) == SIG_ERR) { ? ? ? ? perror ("signal"); ? ? ? ? return -1; ? ? } ? ? int reqid = msgget (KEY_REQUEST, 0); ? ? if (reqid == -1) { ? ? ? ? perror ("msgget"); ? ? ? ? return -1; ? ? } ? ? int resid = msgget (KEY_RESPOND, 0); ? ? if (resid == -1) { ? ? ? ? perror ("msgget"); ? ? ? ? return -1; ? ? } ? ? printf ("取款服務:啟動就緒。 "); ? ? for (;;) { ? ? ? ? WITHDRAW_REQUEST req; ? ? ? ? if (msgrcv (reqid, &req, sizeof (req) - sizeof (req.type), ? ? ? ? ? ? TYPE_WITHDRAW, 0) == -1) { ? ? ? ? ? ? perror ("msgrcv"); ? ? ? ? ? ? continue; ? ? ? ? } ? ? ? ? WITHDRAW_RESPOND res = {req.pid, ""}; ? ? ? ? ACCOUNT acc; ? ? ? ? if (get (req.id, &acc) == -1) { ? ? ? ? ? ? sprintf (res.error, "無效賬號!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? if (strcmp (req.name, acc.name)) { ? ? ? ? ? ? sprintf (res.error, "無效戶名!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? if (strcmp (req.passwd, acc.passwd)) { ? ? ? ? ? ? sprintf (res.error, "密碼錯誤!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? if (req.money > acc.balance) { ? ? ? ? ? ? sprintf (res.error, "余額不足!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? acc.balance -= req.money; ? ? ? ? if (update (&acc) == -1) { ? ? ? ? ? ? sprintf (res.error, "更新賬戶失??!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? res.balance = acc.balance; send_respond: ? ? ? ? if (msgsnd (resid, &res, sizeof (res) - sizeof (res.type), ? ? ? ? ? ? 0) == -1) { ? ? ? ? ? ? perror ("msgsnd"); ? ? ? ? ? ? continue; ? ? ? ? } ? ? } ? ? return 0; }
//查詢子進程(query.c) void sigint (int signum) { ? ? printf ("查詢服務:即將停止。 "); ? ? exit (0); } int main (void) { ? ? if (signal (SIGINT, sigint) == SIG_ERR) { ? ? ? ? perror ("signal"); ? ? ? ? return -1; ? ? } ? ? int reqid = msgget (KEY_REQUEST, 0); ? ? if (reqid == -1) { ? ? ? ? perror ("msgget"); ? ? ? ? return -1; ? ? } ? ? int resid = msgget (KEY_RESPOND, 0); ? ? if (resid == -1) { ? ? ? ? perror ("msgget"); ? ? ? ? return -1; ? ? } ? ? printf ("查詢服務:啟動就緒。 "); ? ? for (;;) { ? ? ? ? QUERY_REQUEST req; ? ? ? ? if (msgrcv (reqid, &req, sizeof (req) - sizeof (req.type), ? ? ? ? ? ? TYPE_QUERY, 0) == -1) { ? ? ? ? ? ? perror ("msgrcv"); ? ? ? ? ? ? continue; ? ? ? ? } ? ? ? ? QUERY_RESPOND res = {req.pid, ""}; ? ? ? ? ACCOUNT acc; ? ? ? ? if (get (req.id, &acc) == -1) { ? ? ? ? ? ? sprintf (res.error, "無效賬號!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? if (strcmp (req.name, acc.name)) { ? ? ? ? ? ? sprintf (res.error, "無效戶名!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? if (strcmp (req.passwd, acc.passwd)) { ? ? ? ? ? ? sprintf (res.error, "密碼錯誤!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? res.balance = acc.balance; send_respond: ? ? ? ? if (msgsnd (resid, &res, sizeof (res) - sizeof (res.type), ? ? ? ? ? ? 0) == -1) { ? ? ? ? ? ? perror ("msgsnd"); ? ? ? ? ? ? continue; ? ? ? ? } ? ? } ? ? return 0; }
//轉賬子進程(transfer) void sigint (int signum) { ? ? printf ("轉賬服務:即將停止。 "); ? ? exit (0); } int main (void) { ? ? if (signal (SIGINT, sigint) == SIG_ERR) { ? ? ? ? perror ("signal"); ? ? ? ? return -1; ? ? } ? ? int reqid = msgget (KEY_REQUEST, 0); ? ? if (reqid == -1) { ? ? ? ? perror ("msgget"); ? ? ? ? return -1; ? ? } ? ? int resid = msgget (KEY_RESPOND, 0); ? ? if (resid == -1) { ? ? ? ? perror ("msgget"); ? ? ? ? return -1; ? ? } ? ? printf ("轉賬服務:啟動就緒。 "); ? ? for (;;) { ? ? ? ? TRANSFER_REQUEST req; ? ? ? ? if (msgrcv (reqid, &req, sizeof (req) - sizeof (req.type), ? ? ? ? ? ? TYPE_TRANSFER, 0) == -1) { ? ? ? ? ? ? perror ("msgrcv"); ? ? ? ? ? ? continue; ? ? ? ? } ? ? ? ? TRANSFER_RESPOND res = {req.pid, ""}; ? ? ? ? ACCOUNT acc[2]; ? ? ? ? if (get (req.id[0], &acc[0]) == -1) { ? ? ? ? ? ? sprintf (res.error, "無效賬號!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? if (strcmp (req.name[0], acc[0].name)) { ? ? ? ? ? ? sprintf (res.error, "無效戶名!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? if (strcmp (req.passwd, acc[0].passwd)) { ? ? ? ? ? ? sprintf (res.error, "密碼錯誤!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? if (req.money > acc[0].balance) { ? ? ? ? ? ? sprintf (res.error, "余額不足!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? if (get (req.id[1], &acc[1]) == -1) { ? ? ? ? ? ? sprintf (res.error, "無效對方賬號!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? if (strcmp (req.name[1], acc[1].name)) { ? ? ? ? ? ? sprintf (res.error, "無效對方戶名!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? acc[0].balance -= req.money; ? ? ? ? if (update (&acc[0]) == -1) { ? ? ? ? ? ? sprintf (res.error, "更新賬戶失敗!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? acc[1].balance += req.money; ? ? ? ? if (update (&acc[1]) == -1) { ? ? ? ? ? ? sprintf (res.error, "更新對方賬戶失??!"); ? ? ? ? ? ? goto send_respond; ? ? ? ? } ? ? ? ? res.balance = acc[0].balance; send_respond: ? ? ? ? if (msgsnd (resid, &res, sizeof (res) - sizeof (res.type), ? ? ? ? ? ? 0) == -1) { ? ? ? ? ? ? perror ("msgsnd"); ? ? ? ? ? ? continue; ? ? ? ? } ? ? } ? ? return 0; }
//封裝的庫(lib.c) const char* ID_FILE = "id.dat"; int genid (void) { ? ? int id = 1000; ? ? int fd = open (ID_FILE, O_RDWR | O_CREAT, 0644); ? ? if (fd == -1) { ? ? ? ? perror ("open"); ? ? ? ? return -1; ? ? } ? ? if (read (fd, &id, sizeof (id)) == -1) { ? ? ? ? perror ("read"); ? ? ? ? return -1; ? ? } ? ? id++; ? ? if (lseek (fd, 0, SEEK_SET) == -1) { ? ? ? ? perror ("lseek"); ? ? ? ? return -1; ? ? } ? ? if (write (fd, &id, sizeof (id)) == -1) { ? ? ? ? perror ("write"); ? ? ? ? return -1; ? ? } ? ? close (fd); ? ? return id; } int save (const ACCOUNT* acc) { ? ? char pathname[PATH_MAX+1]; ? ? sprintf (pathname, "%d.acc", acc -> id); ? ? int fd = creat (pathname, 0644); ? ? if (fd == -1) { ? ? ? ? perror ("creat"); ? ? ? ? return -1; ? ? } ? ? if (write (fd, acc, sizeof (*acc)) == -1) { ? ? ? ? perror ("write"); ? ? ? ? return -1; ? ? } ? ? close (fd); ? ? return 0; } int get (int id, ACCOUNT* acc) { ? ? char pathname[PATH_MAX+1]; ? ? sprintf (pathname, "%d.acc", id); ? ? int fd = open (pathname, O_RDONLY); ? ? if (fd == -1) { ? ? ? ? perror ("open"); ? ? ? ? return -1; ? ? } ? ? if (read (fd, acc, sizeof (*acc)) == -1) { ? ? ? ? perror ("read"); ? ? ? ? return -1; ? ? } ? ? close (fd); ? ? return 0; } int update (const ACCOUNT* acc) { ? ? char pathname[PATH_MAX+1]; ? ? sprintf (pathname, "%d.acc", acc -> id); ? ? int fd = open (pathname, O_WRONLY); ? ? if (fd == -1) { ? ? ? ? perror ("open"); ? ? ? ? return -1; ? ? } ? ? if (write (fd, acc, sizeof (*acc)) == -1) { ? ? ? ? perror ("write"); ? ? ? ? return -1; ? ? } ? ? close (fd); ? ? return 0; } int delete (int id) { ? ? char pathname[PATH_MAX+1]; ? ? sprintf (pathname, "%d.acc", id); ? ? if (unlink (pathname) == -1) { ? ? ? ? perror ("unlink"); ? ? ? ? return -1; ? ? } ? ? return 0; }
//庫的聲明(lib.h) #ifndef _LIBFUNC_H #define _LIBFUNC_H #include "../inc/bank.h" int genid (void); int save (const ACCOUNT* acc); int get (int id, ACCOUNT* acc); int update (const ACCOUNT* acc); int delete (int id); #endif // _LIBFUNC_H
?
總結:Linux系統(tǒng)中,msg消息隊列在多進程間通信的使用過程,在實際開發(fā)中應用是非常廣泛的,十分建議初學Linux編程的工程師們去練習這套系統(tǒng),加深消息隊列在多進程間通信的應用,這將具有很大的益處。
評論
查看更多