实验3-文件誊抄实验

Posted fsmly

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实验3-文件誊抄实验相关的知识,希望对你有一定的参考价值。

编程实现多进程并发实现文件誊抄(源码下载)

  利用多个共享内存(有限空间)构成的环形缓冲,将源文件复制到目标文件,实现两个进程的誊抄。

1、首先我们先了解一下后续会用到的execl函数

  (1)exec函数特点:

  当进程调用一种exec函数时,该进程完全由新程序代换,而新程序则从其main函数开始执行。因为调用exec并不创建新进程,所以前后的进程ID并未改变。exec只是用另一个新程序替换了当前进程的正文、数据、堆和栈段。用另一个新程序替换了当前进程的正文、数据、堆和栈段。当前进程的正文都被替换了,那么execl后的语句,即便execl退出了,都不会被执行。

  (2)execl函数:

  Linux下头文件:#include <unistd.h>

  函数定义:int execl(const char *path, const char *arg, ...);

  函数说明:execl()其中后缀"l"代表list也就是参数列表的意思,第一参数path字符指针所指向要执行的文件路径, 接下来的参数代表执行该文件时传递的参数列表:argv[0],argv[1]... 最后一个参数须用空指针NULL作结束。

  函数返回值:成功则不返回值, 失败返回-1, 失败原因存于errno中,可通过perror()打印

  下面是execl函数使用的样例:

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <stdlib.h>
 4 #include <sys/types.h>
 5 #include <sys/stat.h>
 6 #include <string.h>
 7 #include <sys/wait.h>
 8 /**
 9  * execl.c函数实现
10  *
11  */
12 int main(int argc, char* argv[])
13 {
14     pid_t pid = fork();
15     if(pid == -1)
16     {
17         perror("fork error");
18         exit(1);
19     }
20 
21     // 子进程执行程序
22     if(pid == 0)
23     {
24         execl("/home/caoyang/桌面/test_OS/exec/hello", argv[1],NULL);
25         perror("execl");
26         exit(1);
27     }
28     
29     wait(&pid);
30     return 0;
31 }

  execl.c中执行的另一个程序:

 1 #include<stdio.h>
 2 int main(int argc,char *argv[])
 3 {
 4     int i;
 5     printf("hello world
");
 6     printf("argc:%d
",argc);
 7     for(i=0;i<argc;i++)
 8     {
 9         printf("parameter %d is:%s
",i,argv[i]);
10     }
11     return 0;
12 }

  在终端下输入./a.out h1 h2 ;运行结果在终端下显示应该是:

1 hello world
2 argc:1
3 parameter 0 is h1

2、了解一下共享缓冲区的概念

  共享存储区 :共享存储区是UNIX系统中通信速度最高的一种通信机制。该机制可使若干进程共享主存中的某一个区域,且使该区域出现(映射)在多个进程的虚地址空间中。

  技术分享图片

  共享存储区机制只为进程提供了用于实现通信的共享存储区和对共享存储区进行操作的手段,当用户需要使用该机制时,必须自己设置同步和互斥措施才能保证实现正确的通信。

3、Linux下面共享内存接口

  (1)创建、获得一个共享存储区shmget  

  头文件:#include<sys/types.h>、#include<sys/ipc.h>、#include<sys/shm.h>

  函数定义:int shmget(key,size,flag);
  函数参数说明:key_t key; //key是共享存储区的名字;int size, //size是其大小(以字节计);int flag;//flag是用户设置的标志,如IPC_CREAT|0666。IPC_CREAT表示若系统中尚无指名的共享存储区,则由核心建立一个共享存储区;若系统中已有共享存储区,便忽略IPC_CREAT
  (2)共享存储区的附接shmat:从逻辑上将一个共享存储区附接到进程的虚拟地址空间上。

  系统调用格式:virtaddr=shmat(shmid,addr,flag)

  参数定义:char *shmat(shmid,addr,flag);int shmid,flag;char * addr; /*一般使用NULL*/其中,shmid是共享存储区的标识符;addr是用户给定的,将共享存储区附接到进程的虚地址空间;flag为0时,表示可读、可写;返回值是共享存储区所附接到的进程虚地址viraddr

4、代码实现

  (1)初始化工作:

 1 pid_t p[2];
 2 //创建信号灯
 3 int semid;
 4 semid = semget(semKey, 2, IPC_CREAT|0666);
 5     
 6 //创建共享缓冲区
 7 int shmid;
 8 shmid = shmget(shmKey, sizeof(shareBuf), IPC_CREAT|0666);
 9 shareBuf *sBuf = (shareBuf *)shmat(shmid, NULL, 0);
10 sBuf->over = 0; //初始状况下降拷贝文件结束标志设置为0 当get进程中文件读取结束的时候sBuf->over设置为1

  (2)使用execl函数,子进程分别执行读写进程,读文件、写文件名分别在main函数命令行参数第一个和第二个位置

 1 if((p[0] = fork()) == 0) {
 2     execl("/home/caoyang/桌面/OS实验/文件誊抄实验/get", argv[1],NULL);
 3     perror("execl error......
");
 4     exit(1);
 5 } 
 6 if((p[1] = fork()) == 0) {
 7     execl("/home/caoyang/桌面/OS实验/文件誊抄实验/put", argv[2],NULL);
 8     perror("execl error......
");
 9     exit(1);
10 }

  (3)get.c中除了初始化本身进程的信号灯和得到共享缓冲区之外,主要做的就是读取文件:

while(sBuf->over != 1) {
        //执行P操作
        P(semid, 0);
        size = fread(sBuf->data[readNum], sizeof(char), 80, fp); //读取文件内容
        sBuf->length[readNum] = size;
    
        if(size < 80) {
            printf("------reading process have get a blocking......+current_read_size:%d
",count*80+size);
            sBuf->over = 1; //当最后读取内容小于80的时候结束
        } else {
count ++;        
            printf("------reading process have get a blocking......+current_read_size:%d
",count*80);    
            readNum = (readNum + 1) % 10;
        }    
        //执行V操作
        V(semid, 1);
        sleep(0.1);
    }

  (4)put.c同get.c,做写文件操作:

while(1) {
        P(semid, 1);
        if(sBuf->over == 1) {
            //fwrite(sBuf->data[writeNum], sizeof(char), 80, fp);
            V(semid, 0);
            break;
        }
        //不关闭流的情况下,每次读或写数据后,文件指针都会指向下一个待写或者读数据位置的指针
        fwrite(sBuf->data[writeNum], sizeof(char), 80, fp);
        
        count ++;
        printf("++++++writeing process have get a blocking......+current_write_size:%d
",count*80);
        
        writeNum = (writeNum + 1) % 10;
        V(semid, 0);
    }

  (5)另附上本次实验作为共享缓冲区结构体:

typedef struct sharedBuf {
    char data[10][80];
    int length[10];
    int over; //结束标志
}shareBuf;

5、实验结果

  (1)验证可执行程序誊抄的正确性:在终端下输入./mian test1 copy,其中test1是在Linux下面自定义一个可执行程序文件名,copy是誊抄之后的文件

  使用Linux下面cmp命令比较两个文件的正确性,发现没有错误,我们在具体查看一下文件大小长度等信息,在终端输入stat copy test1,查看两个文件的具体信息,发现大小相同

技术分享图片

  (2)验证文本文件誊抄的正确性:在终端下输入./mian source.txt copy.txt,其中source.txt是在Linux下面创建的一个文本文件,copy.txt是誊抄之后的文件

  使用Linux下面cmp命令比较两个文件的正确性,发现没有错误,我们在具体查看一下文件大小长度等信息,在终端输入stat copy.txt source.txt,查看两个文件的具体信息,发现大小相同

技术分享图片



以上是关于实验3-文件誊抄实验的主要内容,如果未能解决你的问题,请参考以下文章

20165318 缓冲区溢出漏洞实验

201555332盛照宗—网络对抗实验1—逆向与bof基础

缓冲区溢出漏洞实验

第十周作业

使用 React 实验性中继片段:缺少属性 '"$fragmentRefs"'

[NTUSTISC pwn LAB 7]Return to libc实验(puts泄露libc中gadget片段定位)