【Linux】实验报告6 进程间通信

实验六 进程间通信

【封面】Linux实验报告
作者|Ricky的水果摊

时间|2022年6月2日


实验目的

了解 Linux系统的通信机制,管道、消息队列、信号量的创建与使用、共享 内存。

实验原理

1. 进程通信概述

1.1 进程通信简介

进程间通信(Inter-Process Communication)是指多个进程之间相互通信,交换信息的方法

Linux环境下,进程的地址空间相互独立,任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程间不能互相访问,要交换数据必须通过内核,在内核中开辟一块缓存区,进程1把数据从用户空间拷贝到内存缓冲区,进程2再从内存缓冲区中把数据读走,内核提供的这种机制称为进程间通信(IPC)

1.2 进程通信目的
  • 传输数据
  • 共享数据/资源
  • 通知事件
  • 进程控制
1.3 进程通信方式
  • 管道/FIFO
  • 消息队列
  • 共享内存
  • 信号量
  • 信号
  • Socket

2. 进程通信的6方式

2.1 Pipe/FIFO

pipe&FIFO视频详解—bilibili

2.2 消息队列

消息队列相关函数详解—CSDN

2.3 共享内存

共享内存相关函数详解—C语言技术网

2.4 信号量

信号量相关函数详解—C语言技术网

2.5 信号

信号视频详解—bilibili


实验作业

1. ftok.c实践

源代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
int main( void )
{
        int i;
        for ( i = 1; i <= 5; i++ )
                printf( "key[%d] = %ul \n", i, ftok( ".", i) );
        exit(0);
}
问题描述

程序的运行结果是什么?请简单分析

程序运行截图

image-20220605222818418

结果分析
  • 代码用一个for循环,生成了5个键值

2. sendmsg.c实践

源代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define BUF_SIZE 256
#define PROJ_ID 32
#define PATH_NAME "."

int main(void) {
        //用户自定义消息缓冲
        struct mymsgbuf {
                long msgtype;
                char ctrlstring[BUF_SIZE];
        } msgbuffer;

        int qid;
        int msglen;
        key_t msgkey;

        //获取键值
        if((msgkey = ftok (PATH_NAME, PROJ_ID)) == -1) {
                perror ("ftok error!\n"); 
        				exit (1); 
        }

        /*创建消息队列*/
        if((qid = msgget (msgkey, IPC_CREAT|0660)) == -1) {
                perror ("msgget error!\n");
                exit (1);
        }

        /*填充消息结构,发送到消息队列*/
        msgbuffer. msgtype = 3;
        strcpy (msgbuffer.ctrlstring , "Hello,message queue");
        msglen = sizeof(msgbuffer) - 4;
        if(msgsnd (qid, &msgbuffer, msglen, 0) == -1) {
                perror ("msgget error!\n");
                exit (1);
        }
        exit(0);
}
问题描述

程序的运行结果是什么?请简单分析

程序运行截图

image-20220605225406184

结果分析
  • 从运行结果来看,本次操作成功把消息"Hello,message queue"写入了消息队列中,无报错提示

3. rcvmsg.c实践

源代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define BUF_SIZE 256
#define PROJ_ID 32
#define PATH_NAME "."
int main(void) {
        struct mymsgbuf{
                long msgtype;
                char ctrlstring[BUF_SIZE];
        } msgbuffer;

        int qid,msglen;
        key_t msgkey;

        if((msgkey = ftok(PATH_NAME, PROJ_ID)) == -1){
                perror("ftok error!\n");
                exit(1);
        }

        if((qid = msgget(msgkey, IPC_CREAT|0660)) == -1){
                perror ("msgget error!\n");
                exit (1);
        }

        msglen = sizeof(struct mymsgbuf) - 4;

        if (msgrcv(qid, &msgbuffer, msglen, 3, 0) == -1){
                perror ("msgrcv error!\n");
                exit (1);
        }

        printf("Get message %s\n", msgbuffer.ctrlstring);
        exit(0);
}
问题描述

编译运行,分析程序运行结果

程序运行截图

image-20220605231002981

结果分析
  • 从运行结果来看,本次操作成功读取了sendmsg.c中写入消息队列中的消息,并且将其输出在屏幕上

4. server.c / client.c实践

server.c源代码
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/sem.h>
#include <linux/sem.h>
#include <unistd.h>
#define MAX_RESOURCE 5
int main(void) {
        key_t key;
        int semid;
        struct sembuf sbuf = {0, -1, IPC_NOWAIT};
        union semun semopts;
        if ((key = ftok(".", 's')) == -1) {
                perror ("ftok error!\n");
                exit (1);
        }

        if ((semid = semget (key,1,IPC_CREAT|0666)) == -1) {
                perror ("semget error!\n");
                exit (1);
        }

        semopts.val = MAX_RESOURCE;
        if (semctl (semid,0,SETVAL, semopts) == -1) {
                perror ("semctl error!\n");
                exit (1);
        }

        while (1){
                if(semop(semid, &sbuf, 1) == -1) {
                        perror ("semop error!\n");
                        exit (1);
                }
                sleep (3);
        }
        exit (0);
}
client.c源代码
#include <stdio.h>
#include <sys/types.h>
#include <linux/sem.h>
#include <unistd.h>
#include <stdlib.h>
int main(void)
{
        key_t key;
        int semid, semval;
        union semun semopts;

        if((key = ftok (".",'s')) == -1) {
                perror ("ftok error!\n");
                exit (1);
        }
        if((semid = semget (key, 1, IPC_CREAT | 0666)) == -1) {
                perror ("semget error!\n");
                exit (1);
        }

        while(1) {
                if ((semval = semctl(semid, 0, GETVAL, 0)) == -1) {
                        perror ("semctl error!\n");
                        exit (1);
                }
                if (semval > 0) {
                        printf ("Still %d resources can be used\n", semval);
                }else{
                        printf ("No more resources can be used!\n");
                        break;
                }
                sleep (3);
        }
        exit (0);
}
问题描述

首先在终端上编译并运行 server.c再在另外一个终端上编译运行client.c,观察client的运行结果,分析程序的执行过程

程序运行截图

client窗口

image-20220606103627130

server窗口

image-20220606102106981

结果分析
  • 在client窗口,不断输出剩余的可用资源数量
  • 在server窗口,不断对可用资源进行信号量操作,即每3秒减少一个资源

5. wrshm.c / rdshm.c实践

wrshm.c源代码
#include "sharemem.h"
#define SHM_SIZE 1024
int main() {
        int semid, shmid;
        char *shmaddr;
        char write_str[SHM_SIZE];
  
        if ((shmid = createshm (".", 'm', SHM_SIZE)) == -1) {
                exit(1);
        }
        if ((shmaddr = shmat (shmid, (char *)0, 0)) ==(char *)-1) {
                perror ("attach shared memory error!\n");
                exit (1);
        }
        if ((semid = createsem (".", 's', 1, 1)) == -1) {
                exit (1);
        }
  
        while (1) {
                wait_sem (semid, 0);
                sem_p (semid, 0);       /*P操作*/

                printf ("writer: ");
                fgets (write_str, 1024, stdin);
                int len = strlen (write_str) - 1;
                write_str[len] = '\0';
                strcpy (shmaddr, write_str);
                sleep (10);            /*使reader处于阻塞状态*/

                sem_v (semid, 0);      /*V操作*/
                sleep (10);            /*等待reader进行读操作*/
        }
}
rdshm.c源代码
#include "sharemem.h"
int main() {
        int semid, shmid;
        char *shmaddr;

        if ((shmid = createshm(".", 'm', SHM_SIZE)) == -1) {
                exit (1);
        }
        if((shmaddr = shmat (shmid, (char *)0, 0)) == (char *)-1) {
                perror ("attach shared memory error!\n");
                exit (1);
        }
        if((semid = opensem("." ,'s')) == -1) {
                exit (1);
        }

        while(1) {
                printf("reader: ");
                wait_sem(semid,0);  /* 等待信号值为1 */
                sem_p(semid,0);     /* P操作 */

                printf("%s\n", shmaddr);
                sleep(10);         /* 使writer处于阻塞状态 */

                sem_v(semid,0);   /* V操作 */
                sleep(10);        /* 等待writer进行写操作 */
        }
}
sharemen.h源代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <errno.h>
#define SHM_SIZE 1024
union semun{
        int val;
        struct semid_ds *buf;
        unsigned short *array;
};

/*创建信号量函数*/
int createsem (const char * pathname, int proj_id, int members, int init_val) {
        key_t msgkey;
        int index, sid;
        union semun semopts;
        if ((msgkey = ftok(pathname, proj_id)) == -1) {
                perror ("ftok error!\n");
                return -1;
        }
        if ((sid = semget (msgkey, members, IPC_CREAT | 0666)) == -1) {
                perror ("semget call failed.\n");
                return -1;
        }

        /*初始化操作*/
        semopts.val = init_val;
        for (index = 0; index < members; index++) {
                semctl (sid, index, SETVAL, semopts);
        }
        return (sid);
}

/*打开信号量函数*/
int opensem(const char * pathname, int proj_id) {
        key_t msgkey;
        int sid;
        if ((msgkey = ftok(pathname, proj_id)) == -1) {
                perror ("ftok error!\n");
                return -1;
        }
        if ((sid = semget(msgkey, 0, IPC_CREAT | 0666)) == -1) {
                perror("semget call failed.\n");
                return -1;
        }
        return (sid);
}

/*P操作函数*/
int sem_p(int semid, int index) {
        struct sembuf buf = {0,-1,IPC_NOWAIT};
        if (index < 0){
                perror("index of array cannot equals a minus value!");
                return -1;
        }
        buf.sem_num = index;
        if (semop (semid ,& buf,1) == -1) {
                perror ("a wrong operation to semaphore occurred!");
                return -1;
        }
        return 0;
}

/*v操作函数*/
int sem_v (int semid, int index) {
        struct sembuf buf = {0, +1, IPC_NOWAIT};

        if (index < 0) {
                perror("index of array cannot equals a minus value!");
                return -1;
        }

        buf.sem_num = index;
        if (semop (semid,& buf,1) == -1) {
                perror ("a wrong operation to semaphore occurred!");
                return -1;
        }

        return 0;
}

/*删除信号集函数*/
int sem_delete (int semid) {
        return (semctl(semid, 0, IPC_RMID));
}

/*等待信号为1*/
int wait_sem( int semid, int index) {
        while (semctl (semid, index, GETVAL, 0) == 0) {
                sleep (1);
        }
        return 1 ;
}

/*创建共享内存函数*/
int createshm( char * pathname, int proj_id, size_t size) {
        key_t shmkey;
        int sid;

        /*获取键值*/
        if ((shmkey = ftok(pathname, proj_id)) == -1){
                perror("ftok error!\n");
                return -1;
        }

        if ((sid = shmget(shmkey, size, IPC_CREAT | 0666)) == -1) {
                perror ("shmget call failed.\n");
                return -1;
        }
        return (sid);
}
问题描述

编译两个程序,同时在两个终端运行writer和reader,在writer端输入字符串 “hello,reader”,等待一会,看到reader端输出后,在writer.c端的提示符后面输入 字符串“new information”

运行的结果是什么?请分析程序的执行过程

程序运行截图

writer窗口:

image-20220606142627406

reader窗口

image-20220606142552950

结果分析
  • 从运行结果来看,本次操作成功利用共享内存与信号量,完成了writer与reader进程间的通信

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值