联系我:新浪微博@阳光下的云朵2012或者zhangcaiyun_86#163.com(将#换成@)

读书笔记4-------Linux中进程间通信方法

上一篇 / 下一篇  2013-05-17 15:07:16 / 个人分类:linux

卷一  Linux中进程通信方法
第一部分  概述(Linux下进程间通信的几种主要方法简述)
1.管道(Pipe)及有名管道(Named pipe):管道可用于具有亲缘关系进程间的通信,有名管道客服了管道没有名字的限制,因此,除具有管道所具有的的功能外,他还允许无亲缘关系进程间的通信。
2.信号(Singal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期信号语义sigal外,还支持语义符合posix.1标准的信号函数。sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制。又能够同意对外接口,用sigaction函数重新实现了signal函数)(说的啥呀,没看懂就)
3.报文(Message)队列(消息队列):消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式 字节流以及缓冲区大小受限等缺点。
4.共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率低而设计的。往往与其它通信机制,如信号量结合使用,来达到通信间的同步及互斥。
5.信号量(semaphore):主要作为进程间以及统一进程之间的同步手段
6.套接字(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V 的变种都支持套接字。
 
第二部分  详述(Linux下进程间通信)
一  管道
   1.管道是进程间通信中最古老的方式,它包括无名管道有名管道两种,前者用于父进程和子进程间的通信,后者用于运行于同一台机器上的任意连个进程间的通信
  无名管道由pipe()函数创建。
   1.#include<unistd.h>
   2.intpipe(intfiles[2]);
   3.          返回值:若成功则返回0,若出错则返回-1
   经由参数files返回两个文件描述符:files[0]为读而打开,files[1]为写而打开,files[2]的输出是files[0]的输入。
   如下示范父进程和子进程间实现通信:
   #include<stdio.h>
   #include<unistd.h>
  intmain()
  { intfiles[2];
     pid_t pid;
     char buf[256];
    intreturn_count;
  //创建无名管道
  pipe(files);
  //创建子进程
  if((pid=fork())==-1)
  perror("fork() error"):
  return -1;
  }
  //执行子进程
  if(pid==0)
  {printf("in child process....\n");
   //子进程向父进程写数据,关闭管道的读端
   close(files[INPUT]);
   white(files[OUTPUT],“test data”,strlen("test data"));
   exit(0);
  }
  else
  {//执行父进程
   printf("in the parent process...\n");
   //父进程从管道中读取子进程写的数据,关闭管道的写端
   close(files[OUTPUT]);
   return_count=read(files[0],buf.sizeof(buf));
   buf[returned_count]='\0';
   printf("%d bytes of data recetced from spawned process:%s\n",returned_count,buf);
  }
  return  0;
  }
  运行结果:
  in the parent process...
  in  the process...
  9 bytes of data received from spawned process:test data
2.在Linux系统下,有名管道可以由两种方式创建:命令行方式mkmod系统调用函数mkfifo。下面的两种途径都在当前目录下生成一个名为myfifo的有名管道。
  方式一:myfifo("myfifo","rw");
  方式二:mknod myfifo p
 生成了有名管道,就可以使用一般的文件I/O函数,如open、close、read、write等对它进行操作
  如下实例前提:假设已经创建了一个名为myfifo的有名管道。
  //进程一:读有名管道
  #include <stdio.h>
  #include<unistd.h>
  intmain()
 {FILE * in_file;
 intcount=1;
  char buf[80];
  in_file =fopen("myfifo","r");
  if(in_file==NULL)
  {perror("fopen() error");
  return -1;
  while((count = fread(buf,1,80,in_file))>0}
  {printf("received from pipe:%s\n",buf);
   fclose(in_file);
   }
  return 0;
  }
 //进程二  写有名管道
  #include <studio.h>
  #include <unidio.h>
 intmain()
  {FILE * out_file
 intcount=1;
  char buf[80];
  out_file=fopen("myfifo","w");
  if(out_file==NULL)
  { perror("fopen() error");
  return -1;
  }
  sprintf(buf,"this is test data for the named pipe example/n");
  fwrite(buf,1,80,out_file);
  fclose(out_file);
  return 0;
  }
二 消息队列
   消息队列用于运行于同一台机器上的进程间通信,它管道很类似,是一个在系统内核中用来保存消息的队列,它在系统内核中是以消息链表的形式出现。消息链表中节点的结构用msg声明。
   事实上,它是一种正逐步被淘汰的通信方式,我们可以用流管道或者套接口的方式来取代它。(所以我们对此方法也不再解释,也建议读者忽略这种方式。)
三报文  在此略;-)
四 共享内存
  共享内存是运行在同一台机器上的进程间通信的最快的方式,因为数据不需要在不用的进程间复制。通常由一个进程创建一块共享内存区,其余进程对这块内存区进行读写。得到共享内存有两种方式:映射/dev/mem设备和内存映像文件。前一种方式不给系统带来额外的开销。但在现实中并不常用,因为它控制存取的将是实际的物理内存,在linux系统下,这只有通过限制linux系统存取的内存才可以做到,这当然不太实际。常用的方式是通过shmXXX函数来实现利用共享内存进行存储的。
  使用共享内存时要掌握的唯一诀窍是多个进程之间对一定存储区d同步访问。若服务器进程正在将数据放入共享内存,则在它做完这一操作之前,客户进程不应当去读取这些数据。
  通常,信号量是用来实现对共享内存访问的同步(记录锁也可以用于这种场合)
   内核为每个共享存储段设置了一个shmid_ds结构。
   若要获得一个共享存储标识符,调用的第一个函数通常是 shmget。
   #include<sys/shm.h>
   int shmget(key_t key,size_t size,int flag);
          返回值:若成功则返回共享内存ID,若出错则返回 -1
          参数size:该共享存储字段的长度(单位:字节)
   
  shmctl函数对共享存储段执行多种操作。
  #include<sys/shm.h>
  int shmctl(int shmid,int cmd struct shmid_ds *buf)
                    返回值:若成功则返回0,若出错则返回-1
  一旦创建了共享存储段,进程就可调用shmat函数将其连接到他的地址空间中。
  #include <sys/shm.h>
  void shmat(int shmid,const void * addr,int flag);
       返回值:若成功则返回共享存储的指针,若出错则返回-1
  参数:shmid 为shmget函数返回的共享内存标识符,addr和flag参数决定了以什么方式来确定连接的地址,函数的返回值即使该进程数据所连接的实际地址,进程可对此进程进行读写操作。
  
五 信号量
  信号量又称为信号灯,它是用来协调不同进程间的数据对象的,最主要的应用是前一节的共享内存方式的进程通信。本质上,信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取状况、一般来说,为了获得共享资源,进程需要执行下列操作。
  (1)测试控制该资源的信号量。
  (2)若此信号量的值为正,则允许进行使用该资源。进程将信号量减1.
  (3)若信号量为0;则该资源目前不可用,进程进入睡眠状态,直至信号量值大于0,进程被唤醒,转入步骤(1)。
  (4)当进程不再使用一个信号量控制的资源时,信号量值加1.如果此时有进程正在睡眠等待此信号量,则唤醒此进程。
   维护信号量状态的是linux内核操作系统而不是用户进程。我们可以从头文件/usr/src/linux/include/linux/sem.h 中看到内核用来维护信号量状态的各个结构的定义。信号量是一个数据集合,用户可以单独使用这一集合的每个元素。要调用的第一个函数是semget,用以获得一个信号量ID。
   semctl函数用来对信号量进行操作。
   int semctl(int  semid,int semnum,int cmd,union semum arg);
   不同的操作使用过cmd参数来实现的,在头文件sem.h中定义了7种不同的操作,实际编程时可参考。
   semop函数自动执行信号量集合上的操作函数。
   int semop(int semid,strut sembuf semoprray[],size_t nops);
   semoparray是一个指针,他指向一个信号量操作数组。nops规定该数组中操作的数量。
六 套接口
  套接口编程时实现Linux系统和其他大多数操作系统中进程间通信的主要方式之一。我们熟悉的WWW服务、FTP服务等都是基于套接口编程来实现的。除了异地的计算机进程外,套接口同样适用于本地同一台计算机内部的进程间通信。

TAG:

 

评分:0

我来说两句

Open Toolbar