码迷,mamicode.com
首页 > 其他好文 > 详细

20155212 2017-2018-1 《信息安全系统设计》第10周学习总结

时间:2017-11-26 21:56:54      阅读:172      评论:0      收藏:0      [点我收藏+]

标签:i/o   types   存在   gid   通道   共享内存   byte   因此   格式   

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);
#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()函数

      #include <stdio.h>
      FILE *popen(const char *command, const char *open_mode);
      int pclose(FILE *stream);
      popen()函数首先调用一个shell,然后把command作为参数传递给shell。这样每次调用popen()函数都需要启动两个进程;但是由于在Linux中,所(parameter expansion)都是由shell执行的,这样command中包含的所有参数扩展都可以在command程序启动之前完成。
    • pipe()函数

      #include <sys/types.h>
      #include <sys/stat.h>
      int mkfifo(const char *fifo_name, mode_t mode);
      popen()函数只能返回一个管道描述符,并且返回的是文件流(file stream),可以使用函数fread()和fwrite()来访问。pipe()函数可以返回两个管道描述符:pipefd[0]和pipefd[1],任何写入pipefd[1]的数据都可pipefd[0]读回;pipe()函数返回的是文件描述符(file descriptor),因此只能使用底层的read()和write()系统调用来访问。pipe()函数通常用来实现父子进程之间的通信。
  • 特点
    • 只支持单向数据流
    • 只能用于具有亲缘关系的进程之间;
    • 没有名字
    • 管道的缓冲区是有限的(管道制存在于内存中,在管道创建时,为缓冲区分配一个页面大小)
    • 管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式,比如多少字节算作一个消息(或命令、或记录)等等
  • 示例: 构造父子进程间任意方向的的数据通道
    • 代码
    • 运行结果

FIFO

  • 原理
  • 特点
  • 示例

信号

  • 原理
  • 特点
  • 示例

消息队列

  • 原理
  • 特点
  • 示例

参考

20155212 2017-2018-1 《信息安全系统设计》第10周学习总结

标签:i/o   types   存在   gid   通道   共享内存   byte   因此   格式   

原文地址:http://www.cnblogs.com/dky20155212/p/7900371.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!