日期:2014-05-16  浏览次数:20836 次

Linux下进程通信

Linux下进程通信
2011年05月07日
  Linux下进程通信的八种方法[连载-记1]:所有方法登场 本连载是我对《Linux Programming by Example》《Linux Aplication Development》《Linux应用开发技术详解》等书中介绍的Linux下进程通信的方法的相关章节作的笔记,具体细节的还请参照以上书籍。本连载是我对《Linux应用开发技术详解》一书中介绍的Linux下进程通信的方法的相关章节作的笔记。
  Linux下进程通信的八种方法:管道(pipe),命名管道(FIFO),内存映射(mapped memeory),消息队列(message queue),共享内存(shared memory),信号量(semaphore),信号(signal),套接字(Socket). 
  (1) 管道(pipe):管道允许一个进程和另一个与它有共同祖先的进程之间进行通信; 
  (2) 命名管道(FIFO):类似于管道,但是它可以用于任何两个进程之间的通信,命名管道在文件系统中有对应的文件名。命名管道通过命令mkfifo或系统调用mkfifo来创建; 
  (3) 信号(signal):信号是比较复杂的通信方式,用于通知接收进程有某种事情发生,除了用于进程间通信外,进程还可以发送信号给进程本身;Linux除了支持UNIX早期信号语义函数signal外,还支持语义符合POSIX.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD即能实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数的功能); 
  (4) 内存映射(mapped memory):内存映射允许任何多个进程间通信,每一个使用该机制的进程通过把一个共享的文件映射到自己的进程地址空间来实现它; 
  (5) 消息队列(message queue):消息队列是消息的连接表,包括POSIX消息对和System V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能成该无格式字节流以及缓冲区大小受限等缺点; 
  (6) 信号量(semaphore):信号量主要作为进程间以及同进程不同线程之间的同步手段; 
  (7) 共享内存 (shared memory):它使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。这是针对其他通信机制运行效率较低而设计的。它往往与其他通信机制,如信号量结合使用,以达到进程间的同步及互斥; 
  (8) 套接字(Socket):它是更为通用的进程间通信机制,可用于不同机器之间的进程间通信。起初是由UNIX系统的BSD分支开发出来的,但现在一般可以移植到其他类UNIX系统上:Linux和System V的变种都支持套接字;
  linux进程间的同步方法 
  http://buaadallas.blog.51cto.com/399160/171061
  进程间通讯(IPC)方法主要有以下几种: 
  管道/FIFO/共享内存/消息队列/信号 
  1.管道中还有命名管道和非命名管道(即匿名管道)之分,非命名管道(即匿名管道)只能用于父子进程通讯,命名管道可用于非父子进程,命名管道就是FIFO,管道是先进先出的通讯方式 
  2.消息队列是用于两个进程之间的通讯,首先在一个进程中创建一个消息队列,然后再往消息队列中写数据,而另一个进程则从那个消息队列中取数据。需要注意的是,消息队列是用创建文件的方式建立的,如果一个进程向某个消息队列中写入了数据之后,另一个进程并没有取出数据,即使向消息队列中写数据的进程已经结束,保存在消息队列中的数据并没有消失,也就是说下次再从这个消息队列读数据的时候,就是上次的数据!!!! 
  3.信号量,它与WINDOWS下的信号量是一样的,所以就不用多说了 
  4.共享内存,类似于WINDOWS下的DLL中的共享变量,但LINUX下的共享内存区不需要像DLL这样的东西,只要首先创建一个共享内存区,其它进程按照一定的步骤就能访问到这个共享内存区中的数据,当然可读可写 
  以上几种方式的比较: 
  1.管道:速度慢,容量有限,只有父子进程能通讯 
  2.FIFO:任何进程间都能通讯,但速度慢 
  3.消息队列:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题 
  4.信号量:不能传递复杂消息,只能用来同步 
  5.共享内存区:能够很容易控制容量,速度快,但要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全,当然,共享内存区同样可以用作线程间通讯,不过没这个必要,线程间本来就已经共享了同一进程内的一块内存
  进程通信---FIFO 
  http://blogold.chinaunix.net/u3/102839/showart_204 1236.html
  管道没有名字,所以只能在具有血缘关系的进程间使用,而在无名管道发展出来的有名管道FIFO,则有路径名与之相关联,以一种特殊设备文件形式存在于文件系统中,从而允许无亲缘关系的进程访问FIFO,下面看FIFO的详细操作
  1.FIFO的建立
  FIFO是存在于文件系统的文件节点,所以我们可以建立文件节点的mknod系统用来建立它,也可以mkfifo系统调用
  mkfifo说明:
  #include 
  #include 
  int mkfifo(char *path,mode_t mode);
  说明:path:路径名,mode:指定文件存取权标志,mkfifo()会依参数pathname建立特殊的FIFO文件,该文件必须不存在,系统调用已经指定O_CREATE|O_EXCL
  返回:若成功则返回0,否则返回-1,错误原因存于errno中。 
  错误代码 
  EACCESS 参数pathname所指定的目录路径无可执行的权限 
  EEXIST 参数pathname所指定的文件已存在。 
  ENAMETOOLONG 参数pathname的路径名称太长。 
  ENOENT 参数pathname包含的目录不存在 
  ENOSPC 文件系统的剩余空间不足 
  ENOTDIR 参数pathname路径中的目录存在但却非真正的目录。 
  EROFS 参数pathname指定的文件存在于只读文件系统内。
  2.FIFO使用
  创建后,在读写前,要先打开它,用open系统调用
  当使用open()来打开 FIFO文件时,O_NONBLOCK旗标会有影响 
  1、当使用O_NONBLOCK 旗标时,打开FIFO 文件来读取的操作会立刻返回,但是若还没有其他进程打开FIFO 文件来读取,则写入的操作会返回ENXIO 错误代码。 
  2、没有使用O_NONBLOCK 旗标时,打开FIFO 来读取的操作会等到其他进程打开FIFO文件来写入才正常返回。同样地,打开FIFO文件来写入的操作会等到其他进程打开FIFO 文件来读取后才正常返回。
  下面练习,分别写两个程序,一个是服务器程序,不断从管道读取客户发送的信息;另一个是客户程序,在命令行输入信息并从管道发送:
  客户程序(写管道) 
  /*fifo_write.c*/ 
  #include 
  #include 
  #include 
  #include 
  #include 
  #include 
  #include 
  /*FIFO管道路径*/ 
  #define FIFO_SERVER "/tmp/myfifo" 
  main(int argc,char** argv) 
  { 
  int fd = 0; 
  char w_buf[100]; 
  int nwrite; 
  /*打开FIFO管道*/&nb