close
這次作業是要實作類似Gmail Notifier
的電子郵件通知程式,
顯示訊息告知我們有新信件進來
[說明]
本程式(名稱:mybiff,需背景執行)分為以下幾個部分:
1. 在程式裡我們必須使用fork()產生出parent 與child 兩個process。
2. parent 使用getlogin()查詢登入帳號,將查詢回來的帳號套用在 “/var/mail/帳號”,
並判斷如果 “/var/mail/帳號” 的size 變大表示有新信進來(其他情況不考慮),
然後透過KILL 送SIGUSR1 給child 通知它有新信進入。
3. child 必須使用mask 機制,將除了SIGUSR1、 SIGUSR2
以外之所有signal 封鎖(block)起來,然後使用sigsuspend()等待事件發生,
當接收來自parent 送來的SIGUSR1 後,需在螢幕上列印出 “You have new mail !”
4. 在程式中要實作『parent 與child 不能同時寫檔』
--程式需使用一個log 檔(log 檔名與方式不拘),方式為:當有新信進來時,
parent 先寫,child 後寫。
--每當parent 檢查到有新信後,必須先在log 檔中寫入:
“parent : discover new mail 年/月/日 時:分” 訊息,之後發SIGUSR1 給child,
並在parent 中設定一個變數以決定可否進行寫入(可寫入為YES,不可寫入為NO),
並用迴圈不斷偵測變數是否改變。
--child 收到SIGUSR1 後在螢幕上印出 “You have new mail !” 訊息,先在log 檔中寫入
“child: You have new mail 年/月/日 時:分”,然後sleep(20)(即:睡20 秒鐘)再關檔,最後
再發送SIGUSR2 給parent 通知它可以將變數改為YES。
--在child 睡覺的20 秒間,寄信測試程式是否有實作出『parent 與child 不能同時寫檔』。
[實現方法]
1. fork() parent V.S child
因為這次作業需要用到不同的process來做不同的事情
我們需要用到fork()這個函式從原本程式一開始執行的process(parent)新生出一個procees(child)
fork()函式的用法如下:
#include <unistd.h>
pid_t fork(void); // pid_t 為一非負正整數的資料型別 就是每一個process都有他自己的pid
if((pid=fork())==0){ //child pid為一pid_t型別的變數
do something.... //child要做的事
}
else if(pid>0){ //parent
do something... //parent要做的事
}
}
2. (parent部份)檢查登入帳號是否正確 並檢查此帳號的信箱大小
在一開始程式執行時 我們必須檢查目前登入的使用者帳號是否正確
我們使用getlogin()來做這工作
#include <unistd.h>
char *getlogin(void);
Returns: pointer to string giving login name if OK, NULL on error
若檢查無誤後 我們就要來檢查這位使用者的信箱容量大小
這裡我另外寫了一個函式來完成此功能
long get_file_size(const char *filename) //filename即為"/var/mail/帳號”
{
struct stat buf; // stat這個struct之前作業有用過
// 裡面主要是放有各種檔案資訊如大小、名稱等
if(stat(filename,&buf)==-1) { //取得filename(信箱位置)所標示的檔案資訊
printf("stat error\n");
return -1;
}
return (long)buf.st_size; //傳回檔案大小
}
假如發現信箱大小有改變時 我們就要送一個signal給child
這裡是用kill函式來實現
#include <signal.h>
int kill(pid_t pid, int signo); //pid為我們要傳signal的對象(此處為child)
//signo為signal的種類
的電子郵件通知程式,
顯示訊息告知我們有新信件進來
[說明]
本程式(名稱:mybiff,需背景執行)分為以下幾個部分:
1. 在程式裡我們必須使用fork()產生出parent 與child 兩個process。
2. parent 使用getlogin()查詢登入帳號,將查詢回來的帳號套用在 “/var/mail/帳號”,
並判斷如果 “/var/mail/帳號” 的size 變大表示有新信進來(其他情況不考慮),
然後透過KILL 送SIGUSR1 給child 通知它有新信進入。
3. child 必須使用mask 機制,將除了SIGUSR1、 SIGUSR2
以外之所有signal 封鎖(block)起來,然後使用sigsuspend()等待事件發生,
當接收來自parent 送來的SIGUSR1 後,需在螢幕上列印出 “You have new mail !”
4. 在程式中要實作『parent 與child 不能同時寫檔』
--程式需使用一個log 檔(log 檔名與方式不拘),方式為:當有新信進來時,
parent 先寫,child 後寫。
--每當parent 檢查到有新信後,必須先在log 檔中寫入:
“parent : discover new mail 年/月/日 時:分” 訊息,之後發SIGUSR1 給child,
並在parent 中設定一個變數以決定可否進行寫入(可寫入為YES,不可寫入為NO),
並用迴圈不斷偵測變數是否改變。
--child 收到SIGUSR1 後在螢幕上印出 “You have new mail !” 訊息,先在log 檔中寫入
“child: You have new mail 年/月/日 時:分”,然後sleep(20)(即:睡20 秒鐘)再關檔,最後
再發送SIGUSR2 給parent 通知它可以將變數改為YES。
--在child 睡覺的20 秒間,寄信測試程式是否有實作出『parent 與child 不能同時寫檔』。
[實現方法]
1. fork() parent V.S child
因為這次作業需要用到不同的process來做不同的事情
我們需要用到fork()這個函式從原本程式一開始執行的process(parent)新生出一個procees(child)
fork()函式的用法如下:
#include <unistd.h>
pid_t fork(void); // pid_t 為一非負正整數的資料型別 就是每一個process都有他自己的pid
Returns: 0 in child, process ID of child in parent, 1 on error
所以當我們呼叫一次fork後 便要指定parent 跟 child做哪些事
兩個process是同時進行 且無一定先後順序(除非利用傳送signal去block某一個process)
使用格式大略如下:
if((pid=fork())==0){ //child pid為一pid_t型別的變數
do something.... //child要做的事
}
else if(pid>0){ //parent
do something... //parent要做的事
}
}
2. (parent部份)檢查登入帳號是否正確 並檢查此帳號的信箱大小
在一開始程式執行時 我們必須檢查目前登入的使用者帳號是否正確
我們使用getlogin()來做這工作
#include <unistd.h>
char *getlogin(void);
Returns: pointer to string giving login name if OK, NULL on error
若檢查無誤後 我們就要來檢查這位使用者的信箱容量大小
這裡我另外寫了一個函式來完成此功能
long get_file_size(const char *filename) //filename即為"/var/mail/帳號”
{
struct stat buf; // stat這個struct之前作業有用過
// 裡面主要是放有各種檔案資訊如大小、名稱等
if(stat(filename,&buf)==-1) { //取得filename(信箱位置)所標示的檔案資訊
printf("stat error\n");
return -1;
}
return (long)buf.st_size; //傳回檔案大小
}
假如發現信箱大小有改變時 我們就要送一個signal給child
這裡是用kill函式來實現
#include <signal.h>
int kill(pid_t pid, int signo); //pid為我們要傳signal的對象(此處為child)
//signo為signal的種類
Both return: 0 if OK, 1 on error
最後在判斷一個全域變數flag來判斷log檔是否可寫入
YES的話就寫入時間 NO就繼續等待
3. (child部分) 印出收信訊息
當chlid接受到由parent的signal後
先把之前的變數flag改為NO
那怎麼接收signal呢
比如說我們在child要接收SIGUSR1這個signal
我們就在上面fork提到的child部份中使用一個函式如下:
#include <signal.h>
void (*signal(int signo, void (*func)(int)))(int);
Returns: previous disposition of signal if OK, SIG_ERR on error
/*singo為要接收的訊號(如在child就是SIGUSR1)
(*func)(int)) 是一個function pointer的用法
簡單說就是當這個process(child)接受到singo(SIGUSR1)時
就要去執行那個function pointer所指的function裡的動作
這個function一般通稱為signal handler*/
之後便印出收信訊息
因為要避免讓有其他新的signal進來把log檔寫亂
在sleep的過程中 我們必須先把其他不相干的signal先block起來
最後寫完後 一樣用kill送signal給parent
parent也用上述一樣的發是去接收SIGUSR2
4. SIGUSR1 , SIGUSR2
在*nix系統中有很多預設好的signal
如SIGINT 表示發出interrupt的訊號等
這些預設好的signal都是無法更改的
但其中的SIGUSR1 SIGUSR2是可以讓使用者自行去定義它的動作
也就是這個作業一些像寫log檔 sleep等動作
全站熱搜