系统编程-文件操作5

作业

  1. 通过无名管道,让两个子进程间完成相互通信工作
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>

int main()
{
    int pipefd[2]={0};
    int ret=-1;
    ret=pipe(pipefd);
    if(-1==ret)
    {
        perror("pipe");
        return -1;
    }
    pid_t pid=fork();
    if(pid>0)
    {
        pid_t pid2=fork();
        if(pid2>0)
        {
            waitpid(pid,NULL,0);
            waitpid(pid2,NULL,0);
        }
        else if(0==pid2)
        {
            int iSign=0;
            char caBuf[64]={'\0'};
            while(1)
            {
                memset(caBuf,'\0',sizeof(caBuf));
                if(0==iSign)
                {
                    printf("child1-input data:");
                    scanf("%s",caBuf);
                    write(pipefd[1],caBuf,strlen(caBuf));
                    iSign=1;
                }
                else if(1==iSign)
                {
                    read(pipefd[0],caBuf,sizeof(caBuf));
                    printf("child2 says:%s\n",caBuf);
                    iSign=0;
                }
                sleep(1);
            }
        }
        else if(-1==pid2)
        {
            perror("second fork");
            return -1;
        }
    }
    else if(0==pid)
    {
        int iSign=0;
        char caBuf[64]={'\0'};
        while(1)
        {
            memset(caBuf,'\0',sizeof(caBuf));
            if(0==iSign)
            {
                read(pipefd[0],caBuf,sizeof(caBuf));
                printf("child1 says:%s\n", caBuf);
                iSign=1;
            }
            else if(1==iSign)
            {
                printf("child2-input data:");
                scanf("%s",caBuf);
                write(pipefd[1],caBuf,strlen(caBuf));
                iSign=0;
            }
            sleep(1);
        }
    }
    else if(-1==pid)
    {
        perror("first fork");
        return -1;
    }

}

Paste_Image.png
Paste_Image.png

命名管道

  • 创建一个命名管道
#include<sys/types.h>
#include<sys/stat.h>

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>

#define FIFO_PATHNAME "myFifo"
int main(void)
{
    int ret=-1;
    ret=mkfifo(FIFO_PATHNAME,0777);
    if(-1==ret)
    {
        if(EEXIST!=errno)//如果错误等于这个已经存在,我们可以直接运行
        {
            perror("mkfifo");
            exit(EXIT_FAILURE);
        }
    }
    printf("mkfifo is ok\n");

    return 0;
}

Paste_Image.png
  • 在命名管道里插入数据
  1. 首先在一个终端运行写
 #include<sys/types.h>
 #include<sys/stat.h>

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>

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

#define FIFO_PATHNAME "myFifo"
int main(void)
{
    int ret=-1;
    ret=mkfifo(FIFO_PATHNAME,0777);//创建一个管道文件
    if(-1==ret)
    {
        if(EEXIST!=errno)//如果错误等于这个已经存在,我们可以直接运行
        {
            perror("mkfifo");
            exit(EXIT_FAILURE);
        }
    }
    printf("mkfifo is ok\n");
    int fd=-1;
    fd=open(FIFO_PATHNAME,O_WRONLY);
    if(-1==fd)
    {
        perror("open");
        exit(EXIT_FAILURE);
    }
    ret=write(fd,"hello world",11);//没有另一端进行读,所以一直阻塞在那里,直到有读的把他打开
    if(ret>0)
    {
        printf("write %d bytes to fifo\n",ret);
    }
    close(fd);
    return 0;
}


  • 在另外一个终端运行读的程序(这样写的程序才不会阻塞)

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

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>

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

#define FIFO_PATHNAME "myFifo"
int main(void)
{
    int ret=-1;
    ret=mkfifo(FIFO_PATHNAME,0777);//创建一个管道文件
    if(-1==ret)
    {
        if(EEXIST!=errno)//如果错误等于这个已经存在,我们可以直接运行
        {
            perror("mkfifo");
            exit(EXIT_FAILURE);
        }
    }
    printf("mkfifo is ok\n");
    int fd=-1;
    fd=open(FIFO_PATHNAME,O_RDONLY);
    if(-1==fd)
    {
        perror("open");
        exit(EXIT_FAILURE);
    }
    char caBuf[64]={'\0'};
    ret=read(fd,caBuf,sizeof(caBuf));//没有另一端进行读,所以一直阻塞在那里,直到有读的把他打开
    if(ret>0)
    {
        printf("%s\n",caBuf);
        printf("read %d bytes from fifo\n",ret);
    }
    close(fd);
    return 0;
}


  • 管道中的数据,读取了之后,就已经没有数据了
  • 管道两端相互通信
 #include<sys/types.h>
 #include<sys/stat.h>

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FIFO_PATHNAME "myFifo"
int main(void)
{
    int ret=-1;
    ret=mkfifo(FIFO_PATHNAME,0777);//创建一个管道文件
    if(-1==ret)
    {
        if(EEXIST!=errno)//如果错误等于这个已经存在,我们可以直接运行
        {
            perror("mkfifo");
            exit(EXIT_FAILURE);
        }
    }
    printf("mkfifo is ok\n");
    int fd=-1;
    fd=open(FIFO_PATHNAME,O_RDWR);
    if(-1==fd)
    {
        perror("open");
        exit(EXIT_FAILURE);
    }
    int iSign=0;
    char caBuf[64]={'\0'};
    while(1)
    {
        memset(caBuf, '\0', sizeof(caBuf));
        if(iSign==0)
        {
            printf("1.please iput data\n");
            
            scanf("%s",caBuf);
            ret=write(fd,caBuf,strlen(caBuf));//没有另一端进行读,所以一直阻塞在那里,直到有读的把他打开
            if(ret==-1)
            {
                perror("write");
                exit(EXIT_FAILURE);
            }
            iSign=1;
            sleep(1);
        }
        else if(iSign==1)
        {
            ret=read(fd,caBuf,sizeof(caBuf));//没有另一端进行读,所以一直阻塞在那里,直到有读的把他打开
            if(ret==-1)
            {
                perror("read");
                exit(EXIT_FAILURE);
            }   
            printf("1.receive data:%s\n",caBuf);
            iSign=0;
        }
    }
    close(fd);
    return 0;
}


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

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FIFO_PATHNAME "myFifo"
int main(void)
{
    int ret=-1;
    ret=mkfifo(FIFO_PATHNAME,0777);//创建一个管道文件
    if(-1==ret)
    {
        if(EEXIST!=errno)//如果错误等于这个已经存在,我们可以直接运行
        {
            perror("mkfifo");
            exit(EXIT_FAILURE);
        }
    }
    printf("mkfifo is ok\n");
    int fd=-1;
    fd=open(FIFO_PATHNAME,O_RDWR);
    if(-1==fd)
    {
        perror("open");
        exit(EXIT_FAILURE);
    }
    int iSign=0;
    char caBuf[64]={'\0'};
    while(1)
    {
        memset(caBuf, '\0', sizeof(caBuf));
        if(iSign==0)
        {
            printf("1.please iput data\n");
            
            scanf("%s",caBuf);
            ret=write(fd,caBuf,strlen(caBuf));//没有另一端进行读,所以一直阻塞在那里,直到有读的把他打开
            if(ret==-1)
            {
                perror("write");
                exit(EXIT_FAILURE);
            }
            iSign=1;
            sleep(1);
        }
        else if(iSign==1)
        {
            ret=read(fd,caBuf,sizeof(caBuf));//没有另一端进行读,所以一直阻塞在那里,直到有读的把他打开
            if(ret==-1)
            {
                perror("read");
                exit(EXIT_FAILURE);
            }   
            printf("1.receive data:%s\n",caBuf);
            iSign=0;
        }
    }
    close(fd);
    return 0;
}


Paste_Image.png

总结管道的特点(只能在父子进程中使用)

  1. 单向通信
  2. 公共祖先

另一种通信方式(共享内存块)//shmget

  • IPC:进程间的通信
#include <sys/ipc.h>
#include <sys/shm.h>

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>

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

int main(void)
{
    int shmid=-1;
    //第一个参数:key_t key,相当于这块共享内存块的名字
    //第二个参数:这个共享内存块的大小
    shmid=shmget(0x1117,1024,IPC_CREAT);//它是十六进制的数据
    if(-1==shmid)
    {
        perror("shmget");
        exit(EXIT_FAILURE);
    }
    printf("shmget ok:%d\n",shmid);
    return 0;
}

Paste_Image.png
Paste_Image.png
Paste_Image.png
  • 通过这种方法,则不用输入sudo ipcs -m,只需输入 ipcs -m就可以了,因为在程序中已经设置了他的权限
#include <sys/ipc.h>
#include <sys/shm.h>

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>

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

int main(void)
{
    int shmid=-1;
    //第一个参数:key_t key,相当于这块共享内存块的名字
    //第二个参数:这个共享内存块的大小
    shmid=shmget(0x1204,1024,IPC_CREAT | S_IRUSR | S_IWUSR);//它是十六进制的数据
    if(-1==shmid)
    {
        perror("shmget");
        exit(EXIT_FAILURE);
    }
    printf("shmget ok:%d\n",shmid);
    return 0;
}

Paste_Image.png
Paste_Image.png

shmop

  • 创建一个共享内存块,再往里面插入数据,>再显
  • 插入数据
#include <sys/ipc.h>
#include <sys/shm.h>

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>

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

int main(void)
{
    int shmid=-1;
    //第一个参数:key_t key,相当于这块共享内存块的名字
    //第二个参数:这个共享内存块的大小
    shmid=shmget(0x1204,1024,IPC_CREAT | S_IRUSR | S_IWUSR);//它是十六进制的数据
    if(-1==shmid)
    {
        perror("shmget");
        exit(EXIT_FAILURE);
    }
    printf("shmget ok:id=%d\n",shmid);
    void *pRet=NULL;
    pRet=shmat(shmid,NULL,0);//只读打开或者读写打开为0,没有只写打开
    if((void *)-1==pRet)//(void *)-1就是返回值的类型,表示错误的话返回这个
    {
        perror("shmat");
        exit(EXIT_FAILURE);
    }
    char *pData="I want to sleep";
    memcpy(pRet,pData,strlen(pData));//复制指指针变量

    shmdt(pRet);//斩断与内存块的关联
    return 0;
}

Paste_Image.png
  • 读取数据
#include <sys/ipc.h>
#include <sys/shm.h>

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>

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

int main(void)
{
    int shmid=-1;
    //第一个参数:key_t key,相当于这块共享内存块的名字
    //第二个参数:这个共享内存块的大小
    shmid=shmget(0x1204,1024,IPC_CREAT | S_IRUSR | S_IWUSR);//它是十六进制的数据
    if(-1==shmid)
    {
        perror("shmget");
        exit(EXIT_FAILURE);
    }
    printf("shmget ok:id=%d\n",shmid);
    void *pRet=NULL;
    pRet=shmat(shmid,NULL,SHM_RDONLY);//只读打开或者读写打开为0,没有只写打开
    if((void *)-1==pRet)//(void *)-1就是返回值的类型,表示错误的话返回这个
    {
        perror("shmat");
        exit(EXIT_FAILURE);
    }
    char caBuf[32]={'\0'};
    memset(caBuf,'\0',sizeof(caBuf));//最好初始化一下,以免存在野值
    memcpy(caBuf,pRet,sizeof(caBuf));
    printf("%s\n",caBuf);
    shmdt(pRet);//斩断与内存块的关联
    return 0;
}

Paste_Image.png

shmctl 控制共享内存(要最后释放掉共享内存,则用)

#include <sys/ipc.h>
#include <sys/shm.h>

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>

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

int main(void)
{
    int shmid=-1;
    //第一个参数:key_t key,相当于这块共享内存块的名字
    //第二个参数:这个共享内存块的大小
    shmid=shmget(0x1204,1024,IPC_CREAT | S_IRUSR | S_IWUSR);//它是十六进制的数据
    if(-1==shmid)
    {
        perror("shmget");
        exit(EXIT_FAILURE);
    }
    printf("shmget ok:id=%d\n",shmid);
    void *pRet=NULL;
    pRet=shmat(shmid,NULL,SHM_RDONLY);//只读打开或者读写打开为0,没有只写打开
    if((void *)-1==pRet)//(void *)-1就是返回值的类型,表示错误的话返回这个
    {
        perror("shmat");
        exit(EXIT_FAILURE);
    }
    char caBuf[32]={'\0'};
    memset(caBuf,'\0',sizeof(caBuf));//最好初始化一下,以免存在野值
    //数据读取之后,仍然保留在共享内存里面
    //直到下一次写数据的时候被覆盖
    memcpy(caBuf,pRet,sizeof(caBuf));
    printf("%s\n",caBuf);

    struct shmid_ds shmInfo;
    //控制共享内存
    //IPC_STAT:获得共享内存的信息,
    shmctl(shmid,IPC_STAT,&shmInfo);
    printf("shm size= %ld\n",shmInfo.shm_segsz);
    shmctl(shmid,IPC_RMID,0);//消除内存空间
    //shmdt(pRet);//斩断与内存块的关联
    return 0;
}

  • ipcrm +编号(删除某个内存);
  • 将共享内存块映射到进程里

第三种通信方式 mmap(创建一个进程映射到虚拟地址)

  • 将数据写入到这块内存空间
#include <sys/ipc.h>
#include <sys/mman.h>//mmap()
#include <sys/shm.h>

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
    int fd=-1;
    fd=open("test",O_RDWR);//"test"表示当前目录,
    if(-1==fd)
    {
        perror("open");
        exit(-1);
    }
    void *pRet=NULL;
    pRet=mmap(NULL,32,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);//SHARED:其他进程也可以访问,10,偏移量
    if((void *)-1==pRet)
    {
        perror("mmap");
        exit(-1);
    }
    sprintf((char *)pRet,"%s %d %f\n","huihuidashadan",1024,3.14);//与memcpy一样,复制指针,即字符串//将数据格式化的写到这块内存空间里去
    munmap(pRet,32);//取消映射

    return 0;
}

//在test里面插入数据
//运行结果:插入到了test中,如果test里没有数据的话,就会报总线错误(核心已转储)


Paste_Image.png
  • 将数据读取出来
#include <sys/ipc.h>
#include <sys/mman.h>//mmap()
#include <sys/shm.h>

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
    int fd=-1;
    fd=open("test",O_RDWR);//"test"表示当前目录,
    if(-1==fd)
    {
        perror("open");
        exit(-1);
    }
    void *pRet=NULL;
    pRet=mmap(NULL,32,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);//SHARED:其他进程也可以访问,10,偏移量
    if((void *)-1==pRet)
    {
        perror("mmap");
        exit(-1);
    }
    sprintf((char *)pRet,"%s %d %f\n","huihuidashadan",1024,3.14);//与memcpy一样,复制指针,即字符串//将数据格式化的写到这块内存空间里去
    char caBuf[32]={'\0'};
    int iData=0;
    float fData=0;
    sscanf(pRet,"%s%d%f",caBuf,&iData,&fData);//格式化输入数据
    printf("%s %d %.2f\n",caBuf,iData,fData);
    munmap(pRet,32);//取消映射
    close(fd);
    return 0;
}

//


Paste_Image.png

第四种通信方式 (signal):信号

  • A将信号传到内存里,B进程通过信号处理函数处理信号

信号的产生(硬件产生信号,软件产生信号)

  • kill(),产生信号
/*kill()*/
#include<sys/types.h>
#include<signal.h>

/*fork()*/
#include<unistd.h>

#include<stdio.h>
#include<stdlib.h>
int main(void)
{
    pid_t pid=-1;
    pid=fork();
    if(pid>0)
    {
        while(1)
        {
            printf("I am parent,waiting child to kill me\n");
            sleep(1);
        }
    }
    else if(pid==0)
    {
        int i=5;
        while(1)
        {
            if(0==i)
            {
                printf("i kill parent\n");
                kill(getppid(),SIGKILL);//getppid()h获得父进程的进程号
                break;
            }
            else
            {
                printf("still has %d second to kill parent\n",i);
                sleep(1);
            }
            i--;
        }
    }
    else if(pid==-1)
    {
        perror("fork");
        exit(-1);
    }
}


Paste_Image.png
  • 发送一个闹钟信号(alarm信号默认自杀)
#include<stdio.h>
#include<stdlib.h>
#include<stdlib.h>
#include<string.h>
int main(void)
{
    //在指定的秒数之后,给本进程发送一个SIGALRM信号,该信号的默认处理是结束进程
    alarm(5);
    while(1)
    {
        printf("huihuidashabi\n");
        sleep(1);
    }
    return 0;
}

Paste_Image.png

raise,一个信号产生

#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
int main()
{
    int i=5;
    while(1)
    {
        if(i==0)
        {
            raise(SIGKILL);
        }
        printf("ZZZZzzzzz~~~\n");
        i--;
        sleep(1);
    }
}

Paste_Image.png

自定义信号处理

  • kill与stop不能以我们自定义的信号处理方式处理
#include<signal.h>//signal()
#include<stdio.h>
#include<string.h>
typedef void (*sighandler_t)(int);

void sigHandle(int sig)
{
    if(SIGALRM==sig)
    {
        printf("catched sigalrm\n");
    }
}
int main(void)
{
    sighandler_t ret;
    //指定信号的处理方式
    //第一个参数:需要处理特殊处理的信号
    //第二个参数:信号的处理方式
    ret=signal(SIGALRM,sigHandle);
    if(SIG_ERR==ret)
    {
        printf("signal failed\n");
        return -1;
    }
    alarm(3);
    while(1)
    {
    }
    return 0;
}

Paste_Image.png
  • 设置一个信号,Ctrl+c,按下Ctrl+c,z则捕捉到信息
#include<signal.h>//signal()
#include<stdio.h>
#include<string.h>
typedef void (*sighandler_t)(int);
//使用SigHandle
void sigHandle(int sig)
{
    if(SIGALRM==sig)
    {
        printf("catched sigalrm\n");
    }
    else if(SIGINT==sig)
    {
        printf("catched signal\n");
    }
}
int main(void)
{
    
    sighandler_t ret;
    //指定信号的处理方式
    //第一个参数:需要处理特殊处理的信号
    //第二个参数:信号的处理方式
    ret=signal(SIGALRM,sigHandle);
    if(SIG_ERR==ret)
    {
        printf("signal failed\n");
        return -1;
    }
    //SIG_DFL:使用该信号的默认处理动作来处理该信号
    //SIG_IGN:忽略该信号
    ret=signal(SIGINT,sigHandle)
    if(SIG_ERR==ret)
    {
        printf("signal failed\n");
        return -1;
    }
    alarm(3);
    while(1)
    {
    }   
    return 0;
}

//按Ctrl+\键退出运行

Paste_Image.png
#include<signal.h>//signal()
#include<stdio.h>
#include<string.h>
typedef void (*sighandler_t)(int);
//使用SigHandle
void sigHandle(int sig)
{
    if(SIGALRM==sig)
    {
        printf("catched sigalrm\n");
    }
    else if(SIGINT==sig)
    {
        printf("catched signal\n");
    }
}
int main(void)
{
    
    sighandler_t ret;
    //指定信号的处理方式
    //第一个参数:需要处理特殊处理的信号
    //第二个参数:信号的处理方式
    ret=signal(SIGALRM,sigHandle);
    if(SIG_ERR==ret)
    {
        printf("signal failed\n");
        return -1;
    }
    //SIG_DFL:使用该信号的默认处理动作来处理该信号
    //SIG_IGN:忽略该信号
    ret=signal(SIGINT,SIG_IGN);
    if(SIG_ERR==ret)
    {
        printf("signal failed\n");
        return -1;
    }
    alarm(3);
    while(1)
    {
    }   
    return 0;
}

//SIG_IGN:是忽略该信号,所以再按下Ctrl+c已经没有反应了

Paste_Image.png
#include<signal.h>//signal()
#include<stdio.h>
#include<string.h>
typedef void (*sighandler_t)(int);
//使用SigHandle
void sigHandle(int sig)
{
    if(SIGALRM==sig)
    {
        printf("catched sigalrm\n");
    }
    else if(SIGINT==sig)
    {
        printf("catched signal\n");
    }
}
int main(void)
{
    
    sighandler_t ret;
    //指定信号的处理方式
    //第一个参数:需要处理特殊处理的信号
    //第二个参数:信号的处理方式
    ret=signal(SIGALRM,sigHandle);
    if(SIG_ERR==ret)
    {
        printf("signal failed\n");
        return -1;
    }
    //SIG_DFL:使用该信号的默认处理动作来处理该信号
    //SIG_IGN:忽略该信号
    //ret=signal(SIGINT,sigHandle);
    ret=signal(SIGINT,SIG_DFL);
    if(SIG_ERR==ret)
    {
        printf("signal failed\n");
        return -1;
    }
    alarm(3);
    while(1)
    {
    }   
    return 0;
}

//SIG_DFL:使用该信号的默认处理动作来处理该信号

Paste_Image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容