在LINUX系统下, 提供了多种进程间的通信方式,在系统里面能够灵活的运用这些方式, 可以很方便的实现一些功能, 达到事倍功半的效果。
在LINUX下, 通常可以通过fork或者system产生的新的进程, 每一个进程都有一个进程ID来标识该进程。
pipe通信
无名管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
- 函数原型
int pipe(int filedes[2]); 函数说明
pipe()会建立管道,并将文件描述词由参数filedes数组返回。
filedes[0]为管道里的读取端
filedes[1]则为管道的写入端。返回值:
若成功则返回零,否则返回-1,错误原因存于errno中。
错误代码:
EMFILE 进程已用完文件描述词最大量
ENFILE 系统已无文件描述词可用。
EFAULT 参数 filedes 数组地址不合法。
#include <unistd.h>
#include <stdio.h>
int main( void )
{
int filedes[2];
char buf[80];
pid_t pid;
pipe( filedes );
printf("create one pipe: read_id:%d, write_id:%d\n", filedes[0], filedes[1]);
pid=fork();
if (pid > 0)
{
printf( "\nParent process %d, child proces: %d,here write a string to the pipe.\n", getppid(),pid);
char s[] = "Hello world , this is write by pipe.\n";
write( filedes[1], s, sizeof(s) );
printf("write one string:%s into write_id:%d\n", s, filedes[1]);
close( filedes[0] );
close( filedes[1] );
}
else if(pid == 0)
{
printf( "\nChild process %d,here read a string from the pipe.\n", getpid());
read( filedes[0], buf, sizeof(buf) );
printf( "read one string:%s from read_id:%d\n", buf, filedes[0]);
close( filedes[0] );
close( filedes[1] );
}
}
popen 通信
popen() 函数用于创建一个管道:其内部实现为调用 fork 产生一个子进程,执行一个 shell 以运行命令来开启一个进程这个进程必须由 pclose() 函数关闭。
函数原型:
#include “stdio.h”
FILE popen( const char command, const char* mode )参数说明:
command: 是一个指向以 NULL 结束的 shell 命令字符串的指针。这行命令将被传到 bin/sh 并使用 -c 标志,shell 将执行这个命令。
mode: 只能是读或者写中的一种,得到的返回值(标准 I/O 流)也具有和 type 相应的只读或只写类型。如果 type 是 “r” 则文件指针连接到 command 的标准输出;如果 type 是 “w” 则文件指针连接到 command 的标准输入。返回值:
如果调用成功,则返回一个读或者打开文件的指针,如果失败,返回NULL,具体错误要根据errno判断;
#include<stdio.h>
int main(void) {
FILE *fp = NULL;
char buf[10240] = {0};
fp = popen("ls -al","r");
if(fp == NULL){
return 0;
}
fread(buf, 10240, 1, fp);
printf("%s\n",buf);
pclose(fp);
return 0;
}
命名管道(FIFO)
FIFO代表先进先出,但它是一个单向数据流,也就是半双工,和管道不同的是:每个FIFO都有一个路径与之关联,从而允许无亲缘关系的进程访问。
- 函数原型
int mkfifo(const char * pathname,mode_t mode); - 函数说明
mkfifo()会依参数pathname建立特殊的FIFO文件,该文件必须不存在,而参数mode为该文件的权限(mode%~umask),因此 umask值也会影响到FIFO文件的权限。Mkfifo()建立的FIFO文件其他进程都可以用读写一般文件的方式存取。当使用open()来打开 FIFO文件时,O_NONBLOCK旗标会有影响
1、当使用O_NONBLOCK 旗标时,打开FIFO 文件来读取的操作会立刻返回,但是若还没有其他进程打开FIFO 文件来读取,则写入的操作会返回ENXIO 错误代码。
2、没有使用O_NONBLOCK 旗标时,打开FIFO 来读取的操作会等到其他进程打开FIFO文件来写入才正常返回。同样地,打开FIFO文件来写入的操作会等到其他进程打开FIFO 文件来读取后才正常返回。 - 返回值
若成功则返回0,否则返回-1,错误原因存于errno中。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
int main( int argc, char **argv )
{
mode_t mode = 0666;
const char* fifo_path = "/tmp/fifo_test";
char* message = "Hello mkfifo message";
int fd_read, fd_write;
char buf[100] = {0};
if (mkfifo( fifo_path, mode)<0 )
{
printf( "mkfifo err");
return -1;
}
printf("create fifo success.\n");
fd_write = open(fifo_path, "w+");
if (fd_write < 0) {
printf("open fifo write fail\n");
return -1;
}
if (write(fd_write, message, strlen(message)+1) < strlen(message)+1) {
printf("write message err");
return -1;
}
fd_read = open(fifo_path, "r");
if (fd_read < 0) {
printf("open fifo read fail\n");
return -1;
}
while (1) {
if (read(fd_read, buf, 100) != -1 ) {
printf("read fifo message error\n");
return -1;
}
}
printf("success read message:%s\n", buf);
return 0;
}
消息队列通信
请参考: https://www.cnblogs.com/caolicangzhu/p/6985278.html
信号量通信
信号量(semophore )是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
请参考: https://blog.csdn.net/u014338577/article/details/53157124
信号通信
进程间的信号通信, 是进程进通信比较常用的方式, 通过发送信号, 在进程之间通信。
请参考:http://kmoving.blog.163.com/blog/static/205049197201222885035422/
共享内存通信
共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
请参考:https://blog.csdn.net/ljianhui/article/details/10253345
socket 通信
socket通信是使用的最为广泛的进程间通信的方法, 它不仅可以在同一主机上的进程间通信, 还可以进行不同主机之间的通信。