1. 程式人生 > >Linux程序相關API及多程序間通訊

Linux程序相關API及多程序間通訊

一、相關API

1、程序的建立fork()                     #include <unistd.h>                     pid_t fork(void);                     pid_t vfork(void);                         返回值:    > 0       父程序 parent process                                 ==0       子程序 child process                                 < 0(-1)   失敗                         fork的特點:                             第一個特點:    一次呼叫,兩次返回,返回大於0(值就是子程序的id號)表示父程序,等於0表示子程序                                         子程序會複製父程序的所有資源(程式碼段,資料段)                             第二個特點:父程序總共分成三個部分                                         第一個部分在fork之前                                         第二個部分fork成功之後,在id>0情況下的那部分程式碼                                         第三個部分fork後面的                         總結:                             第一點:fork()的套路                                     if(>0){ 父程序程式碼 }else if(==0){ 程式設計師建立子程序需要併發執行的任務程式碼 }else{ 錯誤 }                    

                           第二點:vfork建立的子程序共享父程序的資源,vfork建立的子程序一定優先於父程序執行 2、程序的退出跟回收exit()/wait()                     #include <stdlib.h>                     void exit(int status); //退出程序的同時重新整理緩衝區                     void _exit(int status);//退出程序的時候不重新整理緩衝區                         引數:status -->程序退出時候的值                         對比return:    區別一:return是C語言中關鍵字,exit()是函式                                     區別二:return是返回函式呼叫的結果,exit()是結束整個程序                     #include <sys/wait.h>                     pid_t wait(int *stat_loc);--->收子程序結束返回值(收屍)                         返回值:成功 返回值回收到的那個子程序的ID,失敗 -1                         引數:stat_loc -->用來存放程序退出時候的狀態資訊                                          不是存放退出值,退出值僅僅只是狀態資訊中的一部分                         特點:會讓父程序一直阻塞,直到成功回收到子程序為止                               pid_t waitpid(pid_t pid, int *stat_loc, int options);                         返回值:成功 返回值回收到的那個子程序的ID,失敗 -1                         引數:    pid -->    小於-1   waitpid(-1200,&status,options);回收程序組id是1200的其中一個                                         等於-1   waitpid(-1,&status,options);回收任意一個子程序(不要求同組)                                         等於0    waitpid(0,&status,options); 回收本程序組中任意一個子程序                                         大於0    waitpid(1200,&status,options); 指定回收id是1200的子程序                                 stat_loc -->跟wait一樣                                 options -->WN0HANG  非阻塞等待,等得到就等,等不到就直接退出                                             0        阻塞等待 3、獲取當前程序的id以及父程序的id                     #include <sys/types.h>                     #include <unistd.h>                     pid_t getpid(void);  //獲取子程序ID                     pid_t getppid(void); //獲取父程序ID                     gid_t getgid(void); //獲取程序組ID 4、使用函式執行shell命令                     #include <stdlib.h>                     #include <unistd.h>                     int system(const char *command);                         返回值:失敗 -1                          引數:    command -->你要執行的shell命令或者你要執行程式完整的命令名                     int execl(const char *path, const char *arg, ...);                         引數:    path -->你要執行的程式/命令所在的路徑                                 arg -->你要執行的命令/程式                     int execlp(const char *file, const char *arg, ...);                     int execle(const char *path, const char *arg,..., char * const envp[]);                     int execv(const char *path, char *const argv[]);                     int execvp(const char *file, char *const argv[]);                     int execvpe(const char *file, char *const argv[],char *const envp[]);                         引數:    file-->即將被載入執行的檔名                                 argv-->儲存即將被執行的引數的陣列                                 envp-->使用者自定義的環境變數陣列                         總結:      l -->引數以列表的形式逐一列舉                                  e -->引數中可以設定環境變數                                 v -->引數用一個指標陣列存放                                 p -->傳遞程式/命令的名字

二、程序間通訊

    (一)無名管道和有名管道                 1、建立無名管道                     #include <unistd.h>                     int pipe(int fildes[2]);                         返回值:成功 0 失敗 -1                         引數:    fildes[2] -->存放的是兩個檔案描述符                                 fildes[0]讀端的檔案描述符                                 fildes[1]寫端的檔案描述符                         特點:                             有固定的讀端(fd[0])跟寫端(fd[1])                             當管道中沒有資料可以讀的時候,呼叫read會阻塞                             只能用於具有血緣關係的程序之間(父子程序,兄弟程序之間)                 2、建立有名管道                     #include <sys/types.h>                     #include <sys/stat.h>                     int mkfifo(const char *pathname, mode_t mode);                         返回值:成功 0 失敗 -1                         引數:    pathname -->你要建立的有名管道的名字(帶路徑)                                 mode -->0777                          特點:                             有名字,生成一個管道檔案,用於通訊                             當管道中沒有資料可以讀的時候,呼叫read會阻塞                             任意兩個不同程序之間都能通訊                 3、判斷檔案是否存在                     #include <unistd.h>                     int access(const char *path, int amode);                         功能:判斷一個檔案是否存在,引數用來判斷檔案是否可讀、是否可寫、是否可執行                         返回值:符合你要求的判斷條件返回0  否則 -1                         引數:    path -->檔案的路徑                                 amode -->R_OK, W_OK,  X_OK ,F_OK   (二)訊號:

               作用是當一個程序傳送訊號給另外一個程序的時候,可以通過該訊號去控制另外一個程序執行程式設計師想幹的事情                 1、傳送訊號                     #include <signal.h>                     int kill(pid_t pid, int sig);                         引數:    pid -->你要傳送訊號的那個程序的id                                 sig -->你要傳送的訊號                     int sigqueue(pid_t pid, int sig, const union sigval value);                         引數:union sigval     {                                               int   sival_int;                                               void *sival_ptr; //void *萬能指標                                             };//存放你想傳送的額外資料                         跟kill的區別:sigqueue買一送一(傳送訊號的同時可以額外發送其他資料給到程序)                 2、捕捉訊號並改變訊號的響應動作                     #include <signal.h>                     void (*signal(int sig, void (*func)(int)))(int);                         返回值:最近一次呼叫時第二個引數的值(函式指標)                         引數:sig -->你想要捕捉的訊號                         第二個引數有三種情況:                             情況一:                                 void (*func)(int) -->函式指標,你想要改變的訊號動作就靠該函式實現                             情況二:                                 SIG_DFL -->按照訊號預設的動作響應                             情況三:                                 SIG_IGN -->忽略訊號,收到訊號之後不做任何響應,直接捨棄                         注意:在所有的訊號中有兩個訊號是既不能改變預設動作也不能忽略,SIGKILL和SIGSTOP                     int sigaction(int sig, const struct sigaction *restrict act,struct sigaction *restrict oact);                         引數:    struct sigaction                                 {                                       void(*)(int)          sa_handler //跟signal中函式指標一模一樣                                       sigset_t              sa_mask     //訊號阻塞掩碼??                                       int                   sa_flags     //設定0選擇sa_handler                                                                                     //設定SA_SIGINFO表示選擇sa_sigaction                                       void(*)(int,siginfo_t *,void *)    sa_sigaction//另外一個訊號響應函式,接收額外資料                                 }                                 void(*)(int,siginfo_t *,void *)                                 siginfo_t                                 {                                   si_int -->存放union sigval裡面的sival_int                                   si_ptr -->存放union sigval裡面的sival_ptr                                   si_pid -->存放傳送訊號的那個程序的id                                 }                                 oact-->原有訊號的處理引數,一般為NULL                 3、其它簡單函式                     #include <signal.h>                     int pause(void);//阻塞當前程序等待訊號到來                     int raise(int sig);//自己給自己傳送訊號                     unsigned alarm(unsigned seconds);//定時器,alarm(5);過5秒之後自己給自己傳送SIGALRM                  4、訊號的阻塞或遮蔽                     #include <signal.h>                     int sigprocmask(int how, const sigset_t *restrict set,sigset_t *restrict oset);//設定訊號阻塞的函式                         返回值:成功 0 失敗 -1                         引數:how -->SIG_BLOCK    //設定阻塞 將set對應訊號新增到原本的訊號集合中                                     SIG_SETMASK  //設定阻塞 用set替換原本的訊號集合中的訊號                                     SIG_UNBLOCK  //解除阻塞                              sigset_t --> 系統定義的一種變數型別,專門用來存放你想要阻塞的訊號                                              稱之為訊號阻塞掩碼集                     操作訊號阻塞掩碼集合的函式                     int sigemptyset(sigset_t *set); //清空掩碼集                     int sigfillset(sigset_t *set); //將所有的linux訊號新增到集合中                     int sigaddset(sigset_t *set, int signum);//將具體的某個訊號新增到集合                     int sigdelset(sigset_t *set, int signum);//將具體的某個訊號從集合刪除                     int sigismember(const sigset_t *set, int signum);//判斷某個訊號在不在集合  返回1是成員   返回0不是成員                     注意:訊號設定阻塞僅僅只是將訊號暫時掛起,訊號依然存在(等到解除阻塞又能重新響應)

**********************************************************************************************************************************************      《system-V IPC通訊 》:指的就是共享記憶體,訊息佇列,訊號量             linux命令:    ipcs -s 檢視當前系統所有的訊號量                         ipcs -m 檢視當前系統所有的共享記憶體                         ipcs -q 檢視當前系統所有的訊息佇列                         ipcs -a 檢視當前系統所有的IPC物件                         ipcrm -s 訊號量id  刪除訊號量                         ipcrm -m 共享記憶體id  刪除共享記憶體                         ipcrm -q 訊息佇列id  刪除訊息佇列       (三)訊號量:用來協調多個程序對應共享資源的訪問                 特點:當訊號量的值為0,你還想p操作,會阻塞當前程序                      訊號量的值是不可能為負數的                      v操作永遠不會阻塞                 1、建立訊號量                     #include <sys/sem.h>                     #include <sys/ipc.h>                     int semget(key_t key, int nsems, int semflg);                         返回值:成功 訊號量的id  失敗 -1                         引數:key -->鍵值,確保唯一性                             產生鍵值兩種方法                             第一種:自己隨便寫一個(正整數)                             第二種:使用系統提供的ftok()生成一個鍵值                                 #include <sys/ipc.h>                                 key_t ftok(const char *pathname, int proj_id);                                     返回值:成功 返回鍵值  失敗 -1                                     引數:pathname -->合法的linux路徑                                           proj_id -->隨便寫個整數                                     ftok(".",200);  ftok(".",199);                             nsems -->你打算建立多少個訊號量                             semflg -->IPC_CREAT訊號量不存在則建立                                       IPC_EXCL訊號量已存在則報錯                                       0777    訊號量的訪問許可權                  2、獲取或設定訊號量的相關屬性                     #include <sys/sem.h>                     #include <sys/ipc.h>                     int semctl(int semid, int semnum, int cmd, ...);                         引數:    semid -->訊號量的ID,semget的返回值                                 semnum -->訊號量的序號,從0開始                                 cmd -->GETVAL //獲取訊號量值                                         int value=semctl(id,0,GETVAL);返回值給value                                            SETVAL //設定訊號量值                                         semctl(id,0,SETVAL,10);//將第一個訊號量值設定為10                                        IPC_RMID //刪除訊號量                  3、訊號量的PV操作                     #include <sys/sem.h>                     #include <sys/ipc.h>                     int semop(int semid, struct sembuf *sops, size_t nsops);                         返回值:                         引數:struct sembuf                              {                                   short        sem_num      訊號量的序號                                   short        sem_op       決定你究竟是想P操作還是V操作,負數P操作,正數V操作                                   short        sem_flg      SEM_UNDO(操作完訊號量之後,恢復成原本值)                              }                              nsops -->訊號量struct sembuf個數        (四)共享記憶體:效率最高的IPC                 1、申請共享記憶體                     #include <sys/shm.h>                     #include <sys/ipc.h>                     int shmget(key_t key, size_t size, int shmflg);                         返回值:成功 共享記憶體的ID  失敗 -1                         引數:size -->你打算申請多少的記憶體,位元組,一般設定成512的整數倍                              shmflg->IPC_CREAT共享記憶體不存在則建立                                      IPC_EXCL共享記憶體已存在則報錯                                      0777    共享記憶體的訪問許可權                 2、對共享記憶體進行對映或解除對映                     #include <sys/shm.h>                     #include <sys/ipc.h>                     void *shmat(int shmid, const void *shmaddr, int shmflg);                     int shmdt(const void *shmaddr);                         引數:shmid-->共享記憶體id                              shmaddr -->一般為NULL                              shmflg -->一般為0                         返回值:成功返回共享記憶體的首地址                                 失敗 -1                 3、獲取、設定共享記憶體相關屬性或刪除共享記憶體                     #include <sys/shm.h>                     #include <sys/ipc.h>                     int shmctl(int shmid, int cmd, struct shmid_ds *buf);                         引數:cmd -->IPC_STAT //獲取共享記憶體的屬性資訊                                   IPC_SET //設定共享記憶體的屬性資訊                                   IPC_RMID //刪除共享記憶體                              struct shmid_ds -->用來存放共享記憶體的屬性資訊       (五)訊息佇列                 1、建立訊息佇列                     #include <sys/ipc.h>                     #include <sys/msg.h>                     int msgget(key_t key, int msgflg);                         引數:shmflg->IPC_CREAT訊息佇列不存在則建立                                       IPC_EXCL訊息佇列已存在則報錯                                       0777    訊息佇列的訪問許可權                 2、收發資訊                     #include <sys/ipc.h>                     #include <sys/msg.h>                     int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);                         返回值:成功 0 失敗 -1                         引數:msgflg -->預設設定0   //阻塞                                       IPC_NOWAIT //非阻塞                              msgp--->要傳送資料的儲存區域指標                              msgsz-->要傳送資料的大小                     ssize_t msgrcv(int  msqid,  void *msgp, size_t msgsz, long msgtyp,int msgflg);                         引數:msgtyp -->你要接收的資訊型別                              msgp--->要接收資料的儲存區域指標                              msgsz-->要接收資料的大小                     重點:傳送訊息的格式是有要求的,要求使用者自定資料型別                         struct msgbuf                         {                              long msgtype; //表明訊息型別                              char truemsg[50];//真實的資訊內容                         };                         struct singlelist                         {                                                           int num;//真實的資料                              char buf[10]; //next指標                                                     };                  3、刪除訊息佇列                     #include <sys/ipc.h>                     #include <sys/msg.h>                     int msgctl(int msqid, int cmd, struct msqid_ds *buf);                         引數:cmd-->IPC_STAT 獲取MSG的資訊                                     IPC_SET  設定MSG的資訊                                     IPC_RMID 刪除MSG                               buf-->存放資訊結構體緩衝區