DIY编程器网

 找回密码
 注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 1388|回复: 0
打印 上一主题 下一主题

[待整理] 进程间通信之:实验内容

[复制链接]
跳转到指定楼层
楼主
发表于 2014-10-10 07:33:17 | 只看该作者 |只看大图 回帖奖励 |正序浏览 |阅读模式
        8.7  实验内容

        8.7.1  管道通信实验

        1.实验目的

        通过编写有名管道多路通信实验,读者可进一步掌握管道的创建、读写等操作,同时,也复习使用select()函数实现管道的通信。
         
        2.实验内容

        读者还记得在6.3.3小节中,通过mknod命令创建两个管道的实例吗?本实例只是在它的基础上添加有名管道的创建,而不用再输入mknod命令。
         
        3.实验步骤

        (1)画出流程图。
        该实验流程图如图8.9所示。
       

        图8.9  8.6.1实验流程图

         
        (2)编写代码。
        该实验源代码如下所示。
         
        /* pipe_select.c*/
        #include <fcntl.h>
        #include <stdio.h>
        #include <unistd.h>
        #include <stdlib.h>
        #include <string.h>
        #include <time.h>
        #include <errno.h>
         
        #define FIFO1               "in1"
        #define FIFO2               "in2"
        #define MAX_BUFFER_SIZE         1024          /* 缓冲区大小*/
        #define IN_FILES            3                   /* 多路复用输入文件数目*/
        #define TIME_DELAY          60              /* 超时值秒数 */
        #define MAX(a, b)           ((a > b)?(a):(b))
         
        int main(void)
        {
             int fds[IN_FILES];
             char buf[MAX_BUFFER_SIZE];
             int i, res, real_read, maxfd;
             struct timeval tv;
             fd_set inset,tmp_inset;
            
             fds[0] = 0;        
            
             /* 创建两个有名管道 */
             if (access(FIFO1, F_OK) == -1)
             {
                if ((mkfifo(FIFO1, 0666) < 0) && (errno != EEXIST))
                {
                    printf("Cannot create fifo file\n");
                    exit(1);
                }
             }
             if (access(FIFO2, F_OK) == -1)
             {
                if ((mkfifo(FIFO2, 0666) < 0) && (errno != EEXIST))
                {
                    printf("Cannot create fifo file\n");
                    exit(1);
                }
             }
                
             /* 以只读非阻塞方式打开两个管道文件 */
             if((fds[1] = open (FIFO1, O_RDONLY|O_NONBLOCK)) < 0)
             {
                printf("Open in1 error\n");
                return 1;
             }
            if((fds[2] = open (FIFO2, O_RDONLY|O_NONBLOCK)) < 0)
            {
                printf("Open in2 error\n");
                return 1;
             }
         
             /*取出两个文件描述符中的较大者*/
            maxfd = MAX(MAX(fds[0], fds[1]), fds[2]);
            /*初始化读集合inset,并在读文件描述符集合中加入相应的描述集*/
            FD_ZERO(&inset);
            for (i = 0; i < IN_FILES; i++)
            {
                FD_SET(fds, &inset);
            }
            FD_SET(0, &inset);
         
            tv.tv_sec = TIME_DELAY;
            tv.tv_usec = 0;
            /*循环测试该文件描述符是否准备就绪,并调用select()函数对相关文件描述符做相应操作*/
            while(FD_ISSET(fds[0],&inset)
                     || FD_ISSET(fds[1],&inset) || FD_ISSET(fds[2], &inset))
            {
             /* 文件描述符集合的备份, 免得每次进行初始化 */
                tmp_inset = inset;
                res = select(maxfd + 1, &tmp_inset, NULL, NULL, &tv);
                switch(res)
                {
                    case -1:
                    {
                          printf("Select error\n");
                          return 1;
                      }
                      break;                  
                      case 0: /* Timeout */
                      {
                          printf("Time out\n");
                          return 1;
                   }
                    break;
                    default:
                    {
                          for (i = 0; i < IN_FILES; i++)
                          {
                              if (FD_ISSET(fds, &tmp_inset))
                              {
                                  memset(buf, 0, MAX_BUFFER_SIZE);
                                  real_read = read(fds, buf, MAX_BUFFER_SIZE);
                                  if (real_read < 0)
                                  {
                                      if (errno != EAGAIN)
                                      {
                                          return 1;
                                      }
                                    }
                                   else if (!real_read)
                                   {
                                       close(fds);
                                       FD_CLR(fds, &inset);
                                  }
                                  else
                                  {
                                       if (i == 0)
                                       {/* 主程序终端控制 */
                                          if ((buf[0] == &#39;q&#39;) || (buf[0] == &#39;Q&#39;))
                                           {
                                              return 1;
                                       }
                                       }
                                       else
                                       {/* 显示管道输入字符串 */
                                           buf[real_read] = &#39;\0&#39;;
                                           printf("%s", buf);
                                      }
                               }
                              } /* end of if */
                          } /* end of for */
                     }
                     break;
                  } /* end of switch */
            } /*end of while */
            return 0;
        }
         
        (3)编译并运行该程序。
         
        (4)另外打开两个虚拟终端,分别键入“cat > in1”和“cat > in2”,接着在该管道中键入相关内容,并观察实验结果。
         
        4.实验结果

        实验运行结果与第6章的例子完全相同。
         
        $ ./pipe_select (必须先运行主程序)
        SELECT CALL
        select call
        TEST PROGRAMME
        test programme
        END
        end
        q /* 在终端上输入’q’或’Q’立刻结束程序运行 */
         
        $ cat > in1
        SELECT CALL
        TEST PROGRAMME
        END
         
        $ cat > in2
        select call
        test programme
        end
         
        8.7.2  共享内存实验

        1.实验目的

        通过编写共享内存实验,读者可以进一步了解使用共享内存的具体步骤,同时也进一步加深对共享内存的理解。在本实验中,采用信号量作为同步机制完善两个进程(“生产者”和“消费者”)之间的通信。其功能类似于“消息队列”中的实例,详见8.5.2小节。在实例中使用的与信号量相关的函数,详见8.3.3小节。
         
        2.实验内容

        该实现要求利用共享内存实现文件的打开和读写操作。
         
        3.实验步骤

        (1)画出流程图。
        该实验流程图如图8.10所示。
       

        图8.10  实验8.6.2流程图

         
        (2)编写代码。
        下面是共享内存缓冲区的数据结构的定义。
         
        /* shm_com.h */
        #include <unistd.h>
        #include <stdlib.h>
        #include <stdio.h>
        #include <string.h>
        #include <sys/types.h>
        #include <sys/ipc.h>
        #include <sys/shm.h>
        #define SHM_BUFF_SZ 2048
        struct shm_buff
        {
            int pid;
            char buffer[SHM_BUFF_SZ];
        };
         
        以下是“生产者”程序部分。
         
        /* sem_com.h 和 sem_com.c 与“信号量”小节示例中的同名程序相同 */
        /* producer.c */
        #include "shm_com.h"
        #include "sem_com.h"
        #include <signal.h>
        int ignore_signal(void)
        { /* 忽略一些信号,免得非法退出程序 */
            signal(SIGINT, SIG_IGN);
            signal(SIGSTOP, SIG_IGN);
            signal(SIGQUIT, SIG_IGN);
            return 0;
        }
         
        int main()
        {
            void *shared_memory = NULL;
            struct shm_buff *shm_buff_inst;
            char buffer[BUFSIZ];
            int shmid, semid;
            /* 定义信号量,用于实现访问共享内存的进程之间的互斥*/
              ignore_signal(); /* 防止程序非正常退出 */
            semid = semget(ftok(".", &#39;a&#39;),  1, 0666|IPC_CREAT); /* 创建一个信号量*/
            init_sem(semid);/* 初始值为1 */
         
            /* 创建共享内存 */
            shmid = shmget(ftok(".", &#39;b&#39;), sizeof(struct shm_buff), 0666|IPC_CREAT);
            if (shmid == -1)
            {
                perror("shmget failed");
                del_sem(semid);
                exit(1);
            }
          
         
            /* 将共享内存地址映射到当前进程地址空间 */
            shared_memory = shmat(shmid, (void*)0, 0);
            if (shared_memory == (void*)-1)
            {
                perror("shmat");
                del_sem(semid);
                exit(1);
            }
            printf("Memory attached at %X\n", (int)shared_memory);
            /* 获得共享内存的映射地址 */
            shm_buff_inst = (struct shared_use_st *)shared_memory;
            do
            {
                sem_p(semid);   
                printf("Enter some text to the shared memory(enter &#39;quit&#39; to exit):");
                /* 向共享内存写入数据 */
                    if (fgets(shm_buff_inst->buffer, SHM_BUFF_SZ, stdin) == NULL)
                {
                    perror("fgets");
                    sem_v(semid);
                    break;
                }
                shm_buff_inst->pid = getpid();        
                sem_v(semid);
            } while(strncmp(shm_buff_inst->buffer, "quit", 4) != 0);
         
            /* 删除信号量 */
            del_sem(semid);
            /* 删除共享内存到当前进程地址空间中的映射 */
            if (shmdt(shared_memory) == 1)
            {
                perror("shmdt");
                exit(1);
            }
            exit(0);
        }
         
        以下是“消费者”程序部分。
         
        /* customer.c */
        #include "shm_com.h"
        #include "sem_com.h"
         
        int main()
        {
            void *shared_memory = NULL;
            struct shm_buff *shm_buff_inst;
            int shmid, semid;
            /* 获得信号量 */
            semid = semget(ftok(".", &#39;a&#39;),  1, 0666);
            if (semid == -1)
            {   
                perror("Producer is'nt exist");
                exit(1);
            }
            /* 获得共享内存 */
            shmid = shmget(ftok(".", &#39;b&#39;), sizeof(struct shm_buff), 0666|IPC_CREAT);
            if (shmid == -1)
            {
                perror("shmget");
                exit(1);
            }
            /* 将共享内存地址映射到当前进程地址空间 */
            shared_memory = shmat(shmid, (void*)0, 0);
            if (shared_memory == (void*)-1)
            {
                perror("shmat");
                exit(1);
            }
            printf("Memory attached at %X\n", (int)shared_memory);
            /* 获得共享内存的映射地址 */
            shm_buff_inst = (struct shm_buff *)shared_memory;
            do
            {
                sem_p(semid);
                printf("Shared memory was written by process %d :%s"
        ,                         shm_buff_inst->pid, shm_buff_inst->buffer);
                if (strncmp(shm_buff_inst->buffer, "quit", 4) == 0)
                {
                    break;
                }
                shm_buff_inst->pid = 0;
                memset(shm_buff_inst->buffer, 0, SHM_BUFF_SZ);
                sem_v(semid);
            } while(1);
         
            /* 删除共享内存到当前进程地址空间中的映射 */
            if (shmdt(shared_memory) == -1)
            {
                perror("shmdt");
                exit(1);
            }
            /* 删除共享内存 */
            if (shmctl(shmid, IPC_RMID, NULL) == -1)
            {
                perror("shmctl(IPC_RMID)");
                exit(1);
            }
            exit(0);
        }
         
        4.实验结果

        $./producer
        Memory attached at B7F90000
        Enter some text to the shared memory(enter &#39;quit&#39; to exit):First message
        Enter some text to the shared memory(enter &#39;quit&#39; to exit):Second message
        Enter some text to the shared memory(enter &#39;quit&#39; to exit):quit
        $./customer
        Memory attached at B7FAF000
        Shared memory was written by process 3815 :First message
        Shared memory was written by process 3815 :Second message
        Shared memory was written by process 3815 :quit
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|文字版|手机版|DIY编程器网 ( 桂ICP备14005565号-1 )

GMT+8, 2024-11-30 18:20 , 耗时 0.138877 秒, 22 个查询请求 , Gzip 开启.

各位嘉宾言论仅代表个人观点,非属DIY编程器网立场。

桂公网安备 45031202000115号

DIY编程器群(超员):41210778 DIY编程器

DIY编程器群1(满员):3044634 DIY编程器1

diy编程器群2:551025008 diy编程器群2

QQ:28000622;Email:libyoufer@sina.com

本站由桂林市临桂区技兴电子商务经营部独家赞助。旨在技术交流,请自觉遵守国家法律法规,一旦发现将做封号删号处理。

快速回复 返回顶部 返回列表