查看完整版本: 进程间通信之:实验内容

admin 发表于 2014-10-10 07:33:17

进程间通信之:实验内容

        8.7实验内容

        8.7.1管道通信实验

        1.实验目的

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

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

        (1)画出流程图。
        该实验流程图如图8.9所示。
       
        图8.98.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;
             char buf;
             int i, res, real_read, maxfd;
             struct timeval tv;
             fd_set inset,tmp_inset;
          
             fds = 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 = open (FIFO1, O_RDONLY|O_NONBLOCK)) < 0)
             {
                printf("Open in1 error\n");
                return 1;
             }
          if((fds = open (FIFO2, O_RDONLY|O_NONBLOCK)) < 0)
          {
                printf("Open in2 error\n");
                return 1;
             }
       
             /*取出两个文件描述符中的较大者*/
          maxfd = MAX(MAX(fds, fds), fds);
          /*初始化读集合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,&inset)
                   || FD_ISSET(fds,&inset) || FD_ISSET(fds, &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 == &#39;q&#39;) || (buf == &#39;Q&#39;))
                                           {
                                              return 1;
                                     }
                                     }
                                     else
                                     {/* 显示管道输入字符串 */
                                           buf = &#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;
        };
       
        以下是“生产者”程序部分。
       
        /* 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;
          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
页: [1]
查看完整版本: 进程间通信之:实验内容