20155212 2017-2018-1 《信息安全系統設計》第10周學習總結
20155212 2017-2018-1 《信息安全系統設計》第10周學習總結
stat命令的實現-mysate
- 要求:學習使用stat(1),並用C語言實現
- 學習
stat(1)
- 功能:顯示文件或者文件系統信息
- 語法:
stat [選項] 文件
- 選項參數:
null
:顯示詳細信息-l
:鏈接-f
:不顯示文件的信息,而顯示其所在文件系統的信息-t
:顯示簡潔的信息-c
:以指定格式輸出
man 1 stat
查看stat
命令- 使用
stat
命令
- 使用
man -k stat | grep 2
函數找到如下 - 使用
man 2 stat
查看 使用
stat()
函數會獲得stat結構體struct stat { dev_t st_dev; /* ID of device containing file -文件所在設備的ID*/ ino_t st_ino; /* inode number -inode節點號*/ mode_t st_mode; /* 文件的類型和存取的權限*/ 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 - */ };
其中,比較特殊的是
st_mode
,st_mode是用特征位來表示文件類型的,特征位的定義如下:S_IFMT 0170000 文件類型的位遮罩 S_IFSOCK 0140000 socket S_IFLNK 0120000 符號鏈接(symbolic link) S_IFREG 0100000 一般文件 S_IFBLK 0060000 區塊裝置(block device) S_IFDIR 0040000 目錄 S_IFCHR 0020000 字符裝置(character device) S_IFIFO 0010000 先進先出(fifo) S_ISUID 0004000 文件的(set user-id on execution)位 S_ISGID 0002000 文件的(set group-id on execution)位 S_ISVTX 0001000 文件的sticky位 S_IRWXU 00700 文件所有者的遮罩值(即所有權限值) S_IRUSR 00400 文件所有者具可讀取權限 S_IWUSR 00200 文件所有者具可寫入權限 S_IXUSR 00100 文件所有者具可執行權限 S_IRWXG 00070 用戶組的遮罩值(即所有權限值) S_IRGRP 00040 用戶組具可讀取權限 S_IWGRP 00020 用戶組具可寫入權限 S_IXGRP 00010 用戶組具可執行權限 S_IRWXO 00007 其他用戶的遮罩值(即所有權限值) S_IROTH 00004 其他用戶具可讀取權限 S_IWOTH 00002 其他用戶具可寫入權限 S_IXOTH 00001 其他用戶具可執行權限
判斷文件類型時,用對文件的st_mode的值與文件類型的位遮罩相與,再比較。
stat結構體中很多變量的類型都是不常用的,不能直接輸出該類型,所以使用
grep -r *
查找同名變量的類型。以存儲大小的變量st_size
為例,發現很多使用的long long
類型偽代碼
input path;
struct state;
stat(path,state);
print(state);
- 產品代碼 mystate.c,提交碼雲鏈接
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <time.h> void main(int argc, char *argv[]) { struct stat state; stat(argv[1], &state); printf(" 文件:‘%s‘\n", argv[1]); printf(" 大小:%lld\t", (long long)state.st_size); printf("塊:%lld\t", (long long)state.st_blocks); printf("IO塊:%ld\t", (long)state.st_blksize); switch(state.st_mode & S_IFMT) { case S_IFBLK: printf("塊設備文件"); break; case S_IFCHR: printf("字符設備文件"); break; case S_IFDIR: printf("目錄"); break; case S_IFIFO: printf("管道文件"); break; case S_IFLNK: printf("符號鏈接文件"); break; case S_IFREG: printf("普通文件"); break; case S_IFSOCK: printf("套接字文件"); break; default: break; } printf("\n"); printf("設備:%xh/%ldd\t", (long)state.st_dev, (long)state.st_dev); printf("Inode:%ld\t", (long)state.st_ino); printf("硬鏈接:%ld\n", (long)state.st_nlink); printf("權限:(%o)\t", (unsigned int)(state.st_mode & ~S_IFMT)); printf("Uid:(%ld)\t", (long)state.st_uid); printf("Gid:(%ld)\n", (long)state.st_gid); printf("最近訪問:%s", ctime(&state.st_atim)); printf("最近更改:%s", ctime(&state.st_ctim)); printf("最近改動:%s", ctime(&state.st_mtim)); printf("創建時間:-"); printf("\n"); }
- 測試代碼,mystat 與stat(1)對比,提交截圖
Linux下IPC機制
進程間通信(IPC,Inter-Process Communication)指至少兩個進程或線程間傳送數據或信號的一些技術或方法。
共享內存
共享內存允許兩個或多個進程共享一定的存儲區,因為不需要拷貝數據,所以這是最快的一種IPC。
原理:
共享內存是在多個進程之間共享內存區域的一種進程間的通信方式,由IPC為進程創建的一個特殊地址範圍,它將出現在該進程的地址空間中。其他進程可以將同一段共享內存連接到自己的地址空間中。所有進程都可以訪問共享內存中的地址,就好像它們是malloc分配的一樣。如果一個進程向共享內存中寫入了數據,所做的改動將立刻被其他進程看到。內存頭文件
#include <sys/types.h> #include <sys/stat.h> #include <sys/shm.h>
結構shmid_ds結構體(類似msgid_ds結構體)
strcut shmid_ds{ struct ipc_perm shm_perm; size_t shm_segsz; time_t shm_atime; time_t shm_dtime; ...... }
- 共享內存函數定義
int shmget(key_t key,size_t size,int shmflg); //shmget函數用來創建一個新的共享內存段, 或者訪問一個現有的共享內存段(不同進程只要key值相同即可訪問同一共享內存段)。第一個參數key是ftok生成的鍵值,第二個參數size為共享內存的大小,第三個參數sem_flags是打開共享內存的方式 eg.int shmid = shmget(key, 1024, IPC_CREATE | IPC_EXCL | 0666);//第三個參數參考消息隊列int msgget(key_t key,int msgflag); void *shmat(int shm_id,const void *shm_addr,int shmflg); //shmat函數通過shm_id將共享內存連接到進程的地址空間中。第二個參數可以由用戶指定共享內存映射到進程空間的地址,shm_addr如果為0,則由內核試著查找一個未映射的區域。返回值為共享內存映射的地址 eg.char *shms = (char *)shmat(shmid, 0, 0);//shmid由shmget獲得 int shmdt(const void *shm_addr) //shmdt函數將共享內存從當前進程中分離。 參數為共享內存映射的地址。 eg.shmdt(shms) int shmctl(int shm_id,int cmd,struct shmid_ds *buf);//shmctl函數是控制函數,使用方法和消息隊列msgctl()函數調用完全類似。參數一shm_id是共享內存的句柄,cmd是向共享內存發送的命令,最後一個參數buf是向共享內存發送命令的參數。
- 特點
- 共享內存允許兩個或多個進程共享一定的存儲區,因為不需要拷貝數據,所以這是最快的一種IPC
- 共享內存本身並沒有同步機制,需要程序員使用諸如信號量等手段進行同步控制,增加了其復雜性
- 示例
- 寫進程
代碼
```include
include
include <sys/shm.h>
include
include
include <sys/types.h>
include <sys/ipc.h>
include
define BUF_SIZE 4096
int main()
{
void *shm_addr = NULL;
char buffer[BUF_SIZE];int shmid; // 使用約定的鍵值創建共享內存 shmid = shmget((key_t) 1234, BUF_SIZE, 0666 | IPC_CREAT); printf("shmid : %u\n", shmid); if (shmid < 0) { perror("shmget error!"); exit(1); } // 將共享內存附加到本進程 shm_addr = shmat(shmid, NULL, 0); if (shm_addr == (void *) -1) { perror("shmat error!"); exit(1); } // 寫入數據 bzero(buffer, BUF_SIZE); sprintf(buffer, "Hello, My PID is %u\n", (unsigned int) getpid()); printf("send data: %s\n", buffer); memcpy(shm_addr, buffer, strlen(buffer)); sleep(5); // 分離 if (shmdt(shm_addr) == -1) { printf("shmdt error!\n"); exit(1); }
}
``- 運行結果![](https://images2018.cnblogs.com/blog/1043723/201711/1043723-20171126165304640-412383960.png) -
ipcs -m`命令查看系統中的確存在標識符為15466507的共享內存區域。寫進程已經跟共享內存分離,所以狀態連接數為0 - 讀進程
- 代碼
#include <stdio.h> #include <stdlib.h> #include <sys/shm.h> #include <sys/ipc.h> #include <sys/types.h> #include <unistd.h> #include <string.h> #include <errno.h> #define BUF_SIZE 4096 int main() { void *shm_addr = NULL; int shmid; // 使用約定的鍵值打開共享內存 shmid = shmget((key_t) 1234, BUF_SIZE, IPC_CREAT); printf("shmid : %u\n", shmid); if (shmid == -1) { perror("shmget error!"); exit(1); } // 將共享內存附加到本進程 shm_addr = shmat(shmid, NULL, 0); if (shm_addr == (void *) -1) { perror("shmat error!"); exit(1); } // 讀取數據 char tmp[BUF_SIZE]; bzero(tmp, BUF_SIZE); memcpy(tmp, shm_addr, BUF_SIZE); printf("read from shared memory: %s\n", tmp); sleep(5); // 分離 if (shmdt(shm_addr) == -1) { printf("shmdt error!\n"); exit(1); } // 刪除共享內存 if (shmctl(shmid, IPC_RMID, 0) == -1) { printf("shmctl error!\n"); exit(1); } }
- 運行結果
ipcs -m
查看,沒有15466507的進程,因為讀進程執行完畢後刪除了共享內存區域
- 寫進程
管道
在Linux系統中,我們經常通過符號“|”來使用管道,用以連接兩個或多個命令。實際上,管道是進程與進程間的數據流通道,它使得數據可以以一種“流”的形式在進程間流動。管道也是Unix/Linux系統中一種最常見的進程間通信方式,它在兩個通信進程之間實現一個數據流的通道從而進行信息傳遞。
- 原理
在兩個程序之間傳遞數據的最簡單的方法是使用popen()和pclose()函數
popen()函數首先調用一個shell,然後把command作為參數傳遞給shell。這樣每次調用popen()函數都需要啟動兩個進程;但是由於在Linux中,所(parameter expansion)都是由shell執行的,這樣command中包含的所有參數擴展都可以在command程序啟動之前完成。#include <stdio.h> FILE *popen(const char *command, const char *open_mode); int pclose(FILE *stream);
pipe()函數
popen()函數只能返回一個管道描述符,並且返回的是文件流(file stream),可以使用函數fread()和fwrite()來訪問。pipe()函數可以返回兩個管道描述符:pipefd[0]和pipefd[1],任何寫入pipefd[1]的數據都可pipefd[0]讀回;pipe()函數返回的是文件描述符(file descriptor),因此只能使用底層的read()和write()系統調用來訪問。pipe()函數通常用來實現父子進程之間的通信。#include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *fifo_name, mode_t mode);
- 特點
- 只支持單向數據流
- 只能用於具有親緣關系的進程之間;
- 沒有名字
- 管道的緩沖區是有限的(管道制存在於內存中,在管道創建時,為緩沖區分配一個頁面大小)
- 管道所傳送的是無格式字節流,這就要求管道的讀出方和寫入方必須事先約定好數據的格式,比如多少字節算作一個消息(或命令、或記錄)等等
- 示例: 構造父子進程間任意方向的的數據通道
- 代碼
- 運行結果
FIFO
- 原理
- 特點
- 示例
信號
- 原理
- 特點
- 示例
消息隊列
- 原理
- 特點
- 示例
參考
- 【Linux進程間通信】-共享內存
- linux基礎——linux進程間通信(IPC)機制總結
20155212 2017-2018-1 《信息安全系統設計》第10周學習總結