1. 程式人生 > >Linux下系統函式

Linux下系統函式

Linux下系統函式

rand()函式

獲取02147483647(0RAND_MAX)之間的隨機數。真隨機需要srand()設定種子。一般用時間作為srand()的引數

#include<unistd.h>
int rand(void)
void srand(unsigned int seed)

字元函式

標頭檔案<ctype.h>

函式名 功能
isalnum 測試字元是否為英文或數字
isalpha 測試是否為英文字母
isascii 測試是否為ascii字元
iscntrl 測試是否為ascii控制字元
isdigit 測試是否為阿拉伯數字
islower 測試是否為小寫字母
isprint 測試是否可列印字元
isspace 測試是否空格字元
ispunct 測試是否為標點或特殊符號
isupper 測試是否大寫字母
isxdigit 測試是否16進位制數字

系統時間和日期函式

函式名 功能
asctime 將時間和日期以字串的格式表示
ctime 將時間和日期以字串的格式表示
gettimeofday 獲得當前時間
gmtime 把時間或日期轉為GTM時間
localtime 獲得目前當地的時間和日期
mktime 將時間結構資料轉換為經過的秒數
settimeofday 設定當前時間
time 取得系統當前時間
#include<time.h>
//成功返回秒數,並將結果存入t,失敗返回-1。錯誤原因存在errno中
time_t time(time_t *t)

//傳入時間戳,返回tm結構體
struct tm* gmtime(const time_t *timep)
/***
struct tm
{
    int tm_sec;//秒0~59
    int tm_min;//分0~59
    int tm_hour;//小時0~23
    int tm_mday;//當前月份的日數 0~31
    int tm_mon;//當前月份0~11
    int tm_year;//從1900年到現在的年數
    int tm_wday;//星期,星期一算起0~6
    int tm_yday;//從1月1日起到今天的天數0~365
    int tm_isdst;//夏時制時間
}
**/
//傳入tm結構體時間,返回字串時間
char * asctime(const struct tm *timeptr)
//傳入時間戳,返回tm結構的時間
struct tm * localtime(const time_t *timep)

#include<sys/time.h>
#include<unistd.h>
//
int gettimeofday(struct timeval *tv,struct timezone *tz)
/****
struct timeval{
    long tv_sec;//秒
    long tv_usec;//微秒
}
struct timezone{
    int tz_minuteswest;//和GTM時間差了幾分鐘
    int tz_dsttime;//日光節約時間的狀態
}
***/

環境控制函式

函式名 功能
getenv 取得環境變數的內容
pushenv/setenv 改變或增加環境變數
unsetenv 取消已經改變的環境變數
#include<stdlib.h>
//成功返回環境變數內容,失敗返回NULL
char *getenv(const char * name)
//成功返回0,出錯返回-1。 overwrite  0:忽略value 1:改變成引數value的內容
int setenv(const char *name, const char *value, int overwrite)

記憶體分配函式

函式名 功能
calloc/malloc 分配儲存空間
getpagesize 獲取作業系統中記憶體分頁大小
mmap 建立記憶體對映
munmap 解除記憶體對映
free 釋放分配的記憶體
#include<stdlib.h>
//分配記憶體size塊大小為nmemb的記憶體。失敗返回NULL。calloc會將記憶體初始化為0;
void * calloc(size_t nmemb, size_t size)
//分配size大小的記憶體,失敗返回NULL
void * malloc(size_t size)
#include<unistd.h>
size_t getpagesize(void)
//成功返回對映區的起始地址,失敗返回-1 (MAP_FAILED)
#include<unistd.h>
#include<sys/mman.h>
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offsize)
mmap函式引數:
start:指向對應記憶體的起始地址。通常設為NULL
length:代表檔案中多大的部分對應到記憶體
prot:對映區域的保護方式
    PROT_EXEC:對映區域可被執行
    PROT_READ:對映區域可被讀
    PROT_WRITE:對映區域可被寫
    PROT_NONE:對映區域不能存取
flags:對映區域的特性
    PROT_EXEC:對映區域可被執行
    PROT_READ:對映區域可被讀
    PROT_WRITE:對映區域可被寫
    PROT_NONE:對映區域不能存取
    MAP_FIXED:start所指向的地址無法成功建立對映時,則放棄對映,不對地址做修正。
    MAP_SHARED:對映區域的寫入資料複製迴文件,則允許其他對映該檔案的程序共享
    MAP_PRIVATE:與shared相反,多個程序不共享。
fd:open()返回的檔案描述符
offsize:檔案對映偏移量,0代表從檔案頭開始
注意:呼叫mmap時必須指定MAP_SHARED或MAP_PRIVATE

資料結構中常用函式

函式名 功能
bsearch 二分法搜尋
lfind/lsearch 線性搜尋
qsort 快速排序排列陣列
#include<stdlib.h>
void qsort(void *base,size_t nmemb,size_t size, int (*compar)(const void *,const void *))

void *lfind(const void *key,const void *base,size_t *nmemb, size_t size,int (*compar)(const void *,const void *))

void *bsearch(const void *key,const void *base,size_t nmemb, size_t size,int (*compar)(const void *,const void *))
qsort()函式:
base:陣列的起始地址
nmemb:陣列元素的數量
size:每個元素的大小
compar:函式指標。資料相同返回0,返回1時兩個資料交換,返回-1時兩個資料不交換。

lfind()/lsearch()/bsearch()函式:
key:指向要查詢的資料的指標
base:陣列的起始地址
nmemb:陣列元素的數量
size:每個元素的大小
compar:函式指標。
lfind()和lsearch()不同點在於:當找不到資料時lfind()僅會返回NULL,而不會把資料加入到陣列尾部。lsearch()則會在找不到資料時將其加入陣列尾部

檔案系統API

chmod()函式

修改檔案許可權。成功返回0,失敗返回-1。錯誤存在errno中

#include<sys/types.h>
#include<sys/stat.h>
int chmod(const char* path,mode_t mode)
引數mode 說明
S_IRUSR 所有者具有讀許可權
S_IWUSR 所有者具有寫許可權
S_IXUSR 所有者具有執行許可權
S_IRGRP 組具有讀
S_IWGRP
S_IXGRP
S_IROTH 其他使用者具有讀許可權
S_IWOTH
S_IXOTH

umask()函式

設定新檔案建立時的許可權掩碼

//返回原先的umask的值
mode_t umask(mode_t mask)

stat()函式

獲取檔案屬性。成功返回0,失敗返回-1,錯誤存入errno

#include<sys/stat.h>
#include<unistd.h>
int stat(const char* file_name,struct stat *buf)

struct stat{
    dev_t       st_dev;     /* ID of device containing file -檔案所在裝置的ID*/  
    ino_t       st_ino;     /* inode number -inode節點號*/    
    mode_t      st_mode;    /* protection -保護模式?*/    
    nlink_t     st_nlink;   /* number of hard links -鏈向此檔案的連線數(硬連線)*/    
    uid_t       st_uid;     /* user ID of owner -user id*/    
    gid_t       st_gid;     /* group ID of owner - group id*/    
    dev_t       st_rdev;    /* device ID (if special file) -裝置號,針對裝置檔案*/    
    off_t       st_size;    /* total size, in bytes -檔案大小,位元組為單位*/    
    blksize_t   st_blksize; /* blocksize for filesystem I/O -系統塊的大小*/    
    blkcnt_t    st_blocks;  /* number of blocks allocated -檔案所佔塊數*/    
    time_t      st_atime;   /* time of last access -最近存取時間*/    
    time_t      st_mtime;   /* time of last modification -最近修改時間*/    
    time_t      st_ctime;   /* time of last status change - */
}

scanf系列

#include<stdio.h>
int scanf(const char *format,...)
int fscanf(FILE *fp,const char *format,...)
int sscanf(const char *str,const char *format,...)

不帶快取的檔案IO

函式名 功能
creat 建立檔案
open 開啟或建立檔案
close 關閉檔案
read 讀檔案
write 寫檔案
lseek 移動檔案的讀寫位置
flock 鎖定檔案或解鎖檔案
fcntl 操作檔案描述符
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
//成功返回檔案描述符,失敗返回-1
int creat(const char *pathname,mode_t mode)
//成功返回最小的可用檔案描述符,失敗返回-1
int open(const char* pathname,int flags)
int open(const char* pathname,int flags, mode_t mode)
/***
flags:
    O_RDONLY:只讀
    O_WRONLY:只寫
    O_RDWR:讀寫
    O_APPEND:追加
    O_TRUNG:設定檔案長度為0,且捨棄現存資料
    O_CREAT:沒有則建立檔案,檔案許可權為mode
    O_EXCL:與O_CREAT一起使用,若檔案已經存在,則建立檔案失敗
    O_NONBLOCK:非阻塞式開啟檔案
***/
//成功返回0,失敗返回-1
int close(int fd)

#include<unistd.h>
//成功返回實際讀取或寫入的資料,失敗返回-1
ssize_t read(int fd,void *buf,size_t count)
ssize_t write(int fd,const void *buf,size_t count)

#include<sys/file.h>
//成功返回0,失敗返回-1,錯誤存入errno
int flock(int fd,int operation)
/***
operation:
    LOCK_SH:建立共享鎖,多個程序可同時對一個檔案作共享鎖定
    LOCK_EX:建立互斥鎖。
    LOCK_UN:解除檔案鎖定
    LOCK_NB:無法建立鎖定時,此操作可不被阻斷,馬上返回程序。與SH和EX與運算。
***/
#include<unistd.h>
#include<fcntl.h>
//成功返回0,失敗返回-1,錯誤存入errno
int fcntl(int fd,int cmd)
int fcntl(int fd,int cmd, long arg)
int fcntl(int fd,int cmd, struct flock *lock)

struct flock{
    short l_type;
    short l_whence;
    off_t l_start;
    off_t l_len;
    pid_t l_pid;
}
l_type:
    F_RDLCK:讀鎖
    F_WRLCK:寫鎖
    F_UNLCK:解除鎖
l_whence:SEEK_SET,SEEK_CUR,SEEK_END
l_start:同l_whence
l_len:加鎖長度
l_pid:加鎖的程序id

帶快取的檔案IO

函式名 功能
fopen 開啟或建立檔案
fclose 關閉檔案
fgetc 從檔案讀取一個字元
fputc 將一個字元寫入檔案
fgets 從檔案讀取一字串
fputs 將字串寫入檔案
fread 從檔案流成塊讀取資料
fwrite 將資料成塊寫入檔案
fseek 移動檔案流讀寫位置
rewind 重置檔案流的讀寫位置為檔案開頭
ftell 獲取檔案流的讀取位置
#include<stdio.h>
//成功返回指標,失敗返回NULL
FILE * fopen(const char * path,const char* mode)
/***
mode:
    r:只讀
    r+:開啟可讀寫檔案
    w:只寫。檔案存在則清空檔案,不存在則建立檔案
    w+:開啟可讀寫檔案
    a:追加方式開啟。不存在則建立檔案,存在則在檔案尾部追加內容
    a+:開啟可讀寫檔案
    上面的選項中加入b,則表示用二進位制方式開啟檔案,比如ab+
***/
//成功返回0,失敗返回EOF
int fclose(FILE *stream)
//成功返回讀取的字元,失敗返回EOF
int fgetc(FILE * fp)
//成功返回寫入的字元,失敗返回EOF
int fputc(int ch,FILE *fp)
//成功返回s指標,失敗返回EOF
char * fgets(char *s,int size,FILE *fp)
//成功返回寫入的字元個數,失敗返回EOF
int fputs(const char *str, FILE * fp)
//成功返回實際的讀寫nmemb數,失敗返回EOF
size_t fwrite(const void * ptr,size_t size, size_t nmemb,FILE *fp)
size_t fread(void * ptr, size_t size,size_t nmemb,FILE * fp)
//成功返回0,失敗返回-1
int fseek(FILE *fp, long offset, int whence)
//成功返回檔案當前讀寫位置,失敗返回-1
long ftell(FILE *fp)
//
void rewind(FILE *fp)
特殊檔案操作
目錄檔案
#include<dirent.h>
struct __dirstream
{
    void *__fd; /* `struct hurd_fd' pointer for descriptor.   */
    char *__data; /* Directory block.   */
    int __entry_data; /* Entry number `__data' corresponds to.   */
    char *__ptr; /* Current pointer into the block.   */
    int __entry_ptr; /* Entry number `__ptr' corresponds to.   */
    size_t __allocation; /* Space allocated for the block.   */
    size_t __size; /* Total valid data in the block.   */
    __libc_lock_define (, __lock) /* Mutex lock for this structure.   */
};
typedef struct __dirstream DIR;
struct dirent
{
   long d_ino; /* inode number 索引節點號 */
   off_t d_off; /* offset to this dirent 在目錄檔案中的偏移 */
   unsigned short d_reclen; /* length of this d_name 檔名長 */
   unsigned char d_type; /* the type of d_name 檔案型別 */
   char d_name [NAME_MAX+1]; /* file name (null-terminated) 檔名,最長255字元 */
}
#include<sys/types.h>
#include<dirent.h>
//成功返回DIR指標,失敗返回NULL
DIR *opendir(const char* name)
//成功返回0,失敗返回-1,錯誤存入errno
int closedir(DIR *dir)

#include<sys/types.h>
#include<dirent.h>
#include<fcntl.h>
//成功返回下一個目錄進入點,失敗返回NULL
struct dirent * readdir(DIR *dir)
//返回目錄流當前位置
long int telldir(DIR * dirp)
//loc可以是telldir的返回值。該函式設定目錄流指標的位置
void seekdir(DIR *dirp,long int loc)

#include<sys/types.h>
#include<sys/stat.h>
//建立目錄,同mkdir命令
int mkdir(const char *path, mode_t mode)
#include<unistd.h>
//刪除目錄,但是隻有在目錄為空時才行。同rmdir命令
int rmdir(const char *path)
//切換當前目錄,同cd命令
int chdir(const char * path)
//獲取當前目錄,同pwd命令
char *getcwd(char *buf,size_t size)

連結檔案
#include<unistd.h>
//建立軟連結。成功返回0,失敗返回-1,錯誤存入errno
int symlink(const char * oldpath,const char * newpath)
//建立硬連結。成功返回0,失敗返回-1,錯誤存入errno
int link(const char * oldpath,const char * newpath)
//刪除檔案。成功返回0,失敗返回-1;
int unlink(const char *path)

編寫守護程序

守護程序最重要的特性就是後臺執行,其次是與執行的環境隔開,環境包括檔案描述符,控制終端,會話工作目錄等,這些環境通常是從執行他的父程序(特別是shell)中繼承來的。

編寫守護程序的要點:

  1. 建立子程序,終止父程序。(使之成為殭屍程序)
  2. 在子程序中建立新會話。這個步驟是建立守護程序最重要的一步。需要使用系統函式setsid()。這個函式有三個作用:1,讓程序擺脫原會話的控制;2,讓程序擺脫原程序組的控制;3,讓程序擺脫原控制終端的控制。
  3. 改變工作目錄。可以呼叫chdir()函式將當前工作目錄換為/或/tmp或其他路徑
  4. 重設檔案建立掩碼。
  5. 關閉檔案描述符。從父程序繼承的已經開啟的檔案可能永遠不會被守護程序使用,如果不關閉會導致資源浪費。可能導致所在檔案系統無法解除安裝。
#include<sys/types.h>
#include<unistd.h>
//設定新的組程序號,成功返回程序組號,失敗返回-1,錯誤存入errno
pid_t setsid(void)

示例程式:

#include<unistd.h>
#include<stdio.h>
#include<time.h>
#include<signal.h>
#include<sys/param.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdlib.h>


void init_deamon(void)
{
    pid_t child1,child2;
    int i;
    child1 = fork();//建立子程序,終止父程序
    if(child1 > 0){
        exit(0);
    }else if(child1 < 0){
        perror("建立程序失敗!\n");
        exit(1);
    }
    setsid();//子程序中建立新會話
    chdir("/tmp");//改變工作目錄
    umask(0);//重設umask
    for(i = 0; i < NOFILE;i++){
        close(i);//關閉檔案描述符
    }
    return;
}
int main()
{
    FILE *fp;
    time_t t;
    init_deamon();
    while(1){
        sleep(10);
        if((fp = fopen("deamon.log","a+")) != NULL){
            t = time(0);
            fprintf(fp,"守護程序還在執行,時間是:%s\n",asctime(localtime(&t)));
            fclose(fp);
        }
    }
    return 0;
}
日誌相關函式
#include<syslog.h>
//準備做資訊記錄
void openlog(char * ident, int option, int facility)
/***
option:
    LOG_CONS:如果無法將資訊送到syslogd則直接輸出到控制檯
    LOG_PID:將資訊字串加上產生資訊的程序號PID
    LOG_PERROR:同時輸出到stderr
    LOG_NODELAY:立即開啟連線
    LOG_NOWAIT:不要等待子程序
    LOG_ODELAY:延遲連線的開啟,直到呼叫syslog()
facility:代表資訊種類
    LOG_CRON:由cron或at程式產生的資訊
    LOG_DEAMON:由系統deamon產生的資訊
***/

//將資訊記錄到系統日誌檔案
void syslog(int priority, char * format, ...)
/***
priority:指定資訊種類或等級
    LOG_INFO:提示相關資訊
    LOG_DEBUG:出錯相關資訊
***/

注意以上兩個函式必須具有root許可權才行

程序間通訊

訊號

使用kill -l可以列出系統支援的所有訊號

1~31以SIG開頭(非實時訊號)、34~49以SIGRTMIN開頭是繼承Unix系統的訊號稱為不可靠訊號(非實時訊號)、50~64以SIGRTMAX開頭是對前面不可靠訊號的更改和擴充,稱為可靠訊號(實時訊號)

可靠訊號:支援排隊,使用者傳送一次就註冊一次。

不可靠訊號:不支援排隊,使用者傳送一次,先判斷有沒有相同的訊號已經註冊,如果有則不再註冊。

常見訊號及其預設操作:

訊號名 含義 預設操作
SIGHUP 該訊號在使用者終端連線(正常或非正常)結束時發出 終止
SIGINT 使用者在按下中斷鍵<ctrl+c>時,系統會向該終端相關程序傳送此訊號 終止
SIGQUIT 該訊號在使用者按下<ctrl+>退出鍵時,系統會發送此訊號,造成程序非正常終止 終止
SIGILL 該訊號在一個程序企圖執行一條非法指令時發出(可執行檔案本身錯誤,或者企圖執行資料段堆疊溢位時) 終止
SIGFPE 該訊號在發生致命算術運算錯誤時發出 終止
SIGKILL 用來立即結束程式的執行,且不能被阻塞,處理或忽略 終止
SIGALRM 該訊號在定時器計時完成時發出,定時器可用程序呼叫alarm()函式來設定 終止
SIGSTOP 用於暫停程序,且不能能被阻塞,處理或忽略 暫停程序
SIGTSTP 使用者按下<ctrl+z>掛起鍵時系統傳送此訊號,程序掛起 停止程序
SIGCHLD 該訊號在子程序結束時向父程序發出。當子程序運行了exit()函式,就會向父程序傳送此訊號,如果父程序呼叫了wait()函式,則父程序被喚醒。如果父程序沒有呼叫wait()函式,則忽略此訊號,子程序將變成殭屍程序。 忽略
訊號操作相關函式
函式名 功能
kill 傳送SIGKILL訊號給程序或程序組
raise 傳送訊號給程序或自身
alarm 定時器時間到,向程序傳送SIGALRM訊號
pause 沒有捕捉到訊號前一直將程序掛起
signal 捕捉訊號SIGINT,SIG_IGN,SIG_DFL,SIGQUIT時執行訊號處理函式
sigemptyset 初始化訊號集合為空
sigfillset 初始化訊號集合為所有訊號集合
sigaddset 將指定訊號新增到指定集合
sigdelset 從集合刪除指定訊號
sigismember 查詢指定訊號是否在訊號集合中
sigprocmask 判斷監測或更改訊號遮蔽字
#include<sys/types.h>
#include<signal.h>
//傳送訊號給指定程序。成功返回0,失敗返回-1
int kill(pid_t pid, int sig)
/***
pid:
    pid>0:將訊號傳遞給pid的程序
    pid=0:將訊號傳遞給當前程序相同程序組的所有程序
    pid=-1:將訊號廣播給系統內所有程序
    pid<-1:將訊號傳遞給程序組識別碼為pid絕對值的所有程序
sig:Linux系統訊號
***/
//傳送訊號給當前程序。成功返回0,失敗返回-1
int raise(int sig)
//設定訊號處理函式
void (*signal(int signum,void(*handler)(int))) (int)

#include<signal.h>
//成功返回0,失敗返回-1
int sigemptyset(sigset_t *set)
//成功返回0,失敗返回-1
int sigaddset(sigset_t * set, int signum)
//查詢或設定訊號掩碼。成功返回0,失敗返回-1
int sigprocmask(int how,const sigset_t * set, sigset_t * oldset)
/***
how:
    SIG_BLOCK:新的掩碼有當前訊號掩碼和引數set指定的訊號掩碼作聯集
    SIG_UNBLOCK:將目前訊號掩碼刪除掉引數set指定的訊號掩碼
    SIG_SETMASK:將目前掩碼設定成set指定的掩碼
***/

管道

無名管道

通過pipe()函式實現無名管道建立。無名管道通過int pipe_fd[2];來實現管道的兩端,pipe_fd[0]是讀端,pipe_fd[1]是寫端。

用在父子程序通訊:

  1. 父程序呼叫pipe()開闢管道
  2. 父程序呼叫fork()建立子程序,那麼子程序也繼承得到了相同的管道
  3. 父程序關閉管道讀端,子程序關閉管道寫端,從而就能將資料在父程序寫入,在子程序讀取。如果想實現雙向,那就再使用一個管道。
#include<unistd.h>
//建立無名管道,成功返回0,失敗返回-1
int pipe(int filedes[2])

示例程式:

......
#include<unistd.h>

int main()
{
    int fds[2];
    ......
    
    if(pipe(fds) < 0){
        perror("建立管道失敗\n");
        exit(0);
    }
    ......
    chld = fork();
    if(chld == 0){
        close(fds[1]);
        read(fds[0],buf,100);
        ......
        close(fds[0]);
        ......
    }
    if(chld > 0){
        close(fds[0]);
        write(fds[1],buf,strlen(buf));
        ......
        close(fds[1]);
        waitpid(chld,NULL,0);
        ......
    }
}
命名管道(FIFO)

該管道有名字,所以就能在任何有許可權的程序間使用。

#include<sys/types.h>
#include<sys/stat.h>
//建立命名管道。成功返回0,失敗返回-1,錯誤存入errno
int mkfifo(const char* pathname, mode_t mode)
/***
pathname:指定管道檔案位置,該檔案必須不存在,否則建立失敗。
mode:為建立的管道檔案許可權。跟umask會影響最終的值
***/

#include<stdio.h>
//建立管道IO。成功返回檔案流指標,失敗返回NULL,錯誤存入errno
FILE * popen(const char * command,const char * type)
/***
command:linux命令,例如ls -l等
type:"r","w"分別表示讀,寫。

***/

注意:編寫具有SUID/SGID的程式時,避免使用popen(),因為popen()會繼承環境變數,可能會造成安全問題

示例程式:

......
#include<sys/types.h>
#include<sys/stat.h>

int main()
{
    int rfd,wfd;
    ......
    mkfifo("fifo1",S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
    wfd = open("fifo1",O_WRONLY);    
    ......
    write(wfd,buf,strlen(buf));
    ......
    close(wfd);
    ......
}

......
#include<stdio.h>
int main()
{
    FILE *fp;
    ......
    fp = popen("ls -l","r");
    ......
    fread(buf,sizeof(char),5000,fp);
    ......
    pclose(fp);
    ......
}

訊息佇列

函式名 功能
ftok 由檔案路徑和工程ID生成標準key
msgget 建立或開啟訊息佇列
msgsnd 新增訊息
msgrcv 讀取訊息
msgctl 控制訊息佇列
#include<sys/types.h>
#include<sys/ipc.h>
//成功返回key值,失敗返回-1,錯誤存入errno
key_t ftok(char * pathname,char proj)

#include<sys/types.h>
#include<sys/ipc.h>
#include<sys.msg.h>
//成功返回訊息佇列識別號,失敗返回-1,錯誤存入errno
int msgget(key_t key,int msgflg)
/***
key:ftok函式生成的key,如果傳入IPC_PRIVATE則建立新的訊息佇列
msgflg:決定訊息佇列的存取許可權
***/
//成功返回0,失敗返回-1.錯誤存入errno
int msgsnd(int msgid,struct msgbuf * msgp ,int msgsz,int msgflg)
/***
msgid:訊息佇列識別號
msgp:使用者自定義的結構體指標,形態如下
    struct msgbuf{
        long mtype;//訊息型別,必須大於0
        char mtext[1];//訊息文字
    }
msgsz:訊息的大小
msgflg:用來指明核心程式在訊息佇列沒有訊息的情況下采取的行動
***/
//成功返回實際讀取的訊息資料長度,失敗返回-1,錯誤存入errno
int msgrcv(int msgid,struct msgbuf * msgp,int msgsz,long msgtyp,int msgflg)
/***
msgtyp:用來指定所要讀取的訊息型別。
    =0:返回佇列的第一項訊息
    >0:返回佇列中第一項msgtyp和mtype相同的訊息
    <0:返回佇列第一項mtype小於或等於msgtyp絕對值的訊息
***/
//成功返回0,失敗返回-1,錯誤存入errno
int msgctl(int msgid,int cmd,struct msqid_ds *buf)
/***
cmd:
    IPC_STAT:讀取訊息佇列的資料結構msqid_ds,並將其儲存在buf指定的地址中。
    IPC_SET:設定訊息佇列的資料結構msqid_ds中的ipc_perm元素的值。這個值取自buf引數。
    IPC_RMID:從系統核心中移走訊息佇列。

***/

示例程式:

......
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>

struct msgbuf{
    long mtype;//訊息型別,必須大於0
    char mtext[512];//訊息文字
}

int main()
{
    ......
    key_t key;
    int qid;
    struct msgbuf msg;
    
    key = ftok(".","a");
    ......
    qid = msgget(key,IPC_CREAT | 0666);
    ......
    msg.mtype = getpid();
    strcpy(msg.mtext,"hhhhhhhh");
    ......
    msgsnd(qid,&msg,strlen(msg.mtext),0);
    ......
    msgrcv(qid,&msg,512,0,0);
    ......
    msgctl(qid,IPC_RMID,NULL)
    ......
}

共享記憶體

函式名 功能
mmap 建立共享記憶體對映
munmap 解除共享記憶體對映
shmget 獲取共享記憶體區域ID
shmat 建立對映共享記憶體
shmdt 解除共享記憶體對映
#include<unistd.h>
#include<sys/mman.h>
//建立記憶體對映.成功返回對映去的記憶體起始地址,失敗返回-1,錯誤存入errno
void * mmap(void * start, size_t length, int prot, int flags, int fd, off_t offsize)
/***
prot:對映區域保護方式
    PROT_EXEC:對映區域可被執行
    PROT_READ:對映區域可被讀
    PROT_WRITE:對映區域可被寫
    PROT_NONE:對映區域不能存取
flags:特性
    PROT_EXEC:對映區域可被執行
    PROT_READ:對映區域可被讀
    PROT_WRITE:對映區域可被寫
    PROT_NONE:對映區域不能存取
    MAP_FIXED:start所指向的地址無法成功建立對映時,則放棄對映,不對地址做修正。
    MAP_SHARED:對映區域的寫入資料複製迴文件,則允許其他對映該檔案的程序共享
    MAP_PRIVATE:與shared相反,多個程序不共享。
***/
//成功返回0,失敗返回-1,錯誤存入errno
int munmap(void *start, size_t length)
/****
length:欲取消記憶體的大小
***/

示例程式:

......
#include<unistd.h>
#include<sys/mman.h>

struct people{
  char name[4];
  int age;
};

int main()
{
    pid_t chld;
    people * p_map;
    ......
    
    p_map = (people *)mmap(NULL,sizeof(people)*10,PROT_READ | PROT_WRITE|MAP_SHARED | MAP_ANONYMOUS,-1,0);
    ......
    chld = fork();
    ......
    if(chld == 0){
        for(int i = 0;i < 5;i++){
            printf("第%d個人,姓名:%s,年齡:%d\n",(p_map+i)->name,(p_map+i)->age);
        }
        munmap(p_map,sizeof(people)*10);
        ......
    }
    if(chld > 0){
        for(int i = 0;i < 5;i++){
            memcpy((p_map+i)->name,'a'+i,2);
            (p_map+i)->age = i;
        }
        ......
        munmap(p_map,sizeof(people)*10);
    }
}
UNIX Systeem V共享記憶體
#include<sys/ipc.h>
#include<sys/shm.h>
//成功返回共享記憶體識別號,失敗返回-1,錯誤存入errno
int shmget(key_t key, int size, int shmflg)
/***
key:為IPC_PRIVATE則建立新的共享記憶體,大小有四則決定
***/
//對映共享記憶體,成功返回記憶體的起始地址,失敗返回-1,錯誤存入errno
void * shmat(int shmid, const void * shmaddr, int shmflg)
/***
shmid:共享記憶體識別號
shmaddr:
    =0:核心自動選擇地址
    !=0且shmflg沒有指定SHM_RND旗標,則以引數shmaddr為連線地址。
    !=0且指定SHM_RND旗標:引數shmaddr會自動調整為SHMLBA的整數倍
***/
//成功返回0,失敗返回-1,錯誤存入errno
int shmdt(const void * shmaddr)mmap

mmap和unix system v兩類共享記憶體的區別在於mmap用的普通檔案實現共享記憶體,而unix system v則用的特殊檔案系統shm中的檔案實現共享記憶體。