回顾:
进程间通信方式:
信号,管道
消息队列,共享内存,信号量
sokcet

信号:
本质就是软中断
signal(信号,函数指针);
void func(int);
kill(pid,signo);
raise(signo);
alarm(seconds);
pause();

kill -9 PID

--------------------------------
管道:
1.基本概念:
管道本质上还是以文件作为通信的媒介,该文件比较特殊,叫管道文件
管道分为两类:
无名管道(pipe)和有名管道(fifo)
有名管道:由程序员手动创建,实现任意两个进程之间的通信
无名管道:调用系统函数创建,实现父子进程间的通信。

无名管道的创建与关闭:
管道是基于文件描述符的通信方式,当一个管道建立时,它会创建两个文件描述符fd[0]和fd[1],其中fd[0]固定用于读管道,fd[1]固定写管道,这样构成一个半双工的通道。

管道关闭时,只需将这两个文件描述符关闭即可,使用close函数。

管道创建函数:
int pipe(int pipefd[2]);
功能:用于内核中创建无名管道
pipefd:整形数组,用来存放管道的读写文件描述符
pipefd[0]:用来存放读端的文件描述符
pipefd[1]:用来存放写端的文件描述符
返回:
成功返回0
失败返回-1,errno被设置

管道读写说明:
用pipe()这个函数创建的管道两端处于同一进程之中,因此,在实际中没有太大意义。
通常的做法:先创建一个管道,再通过fork()函数创建一个子进程,子进程会继承父进程所创建的管道,为了实现父子进程间的通信,需要把无关的读端或写端的文件描述符关闭。

管道的特点:
pipe创建的管道是阻塞方式的。
去读一个管道,如果管道里没有数据,则阻塞,直到有数据可读
往管道中写数据,如果管道不可写,则阻塞,直到文件可写。
数据写到管道的写端,内核会把这些数据缓存,直到有进程来读。
数据一旦被读走,就没有了。

---------------------
有名管道
为了克服无名管道的缺点,提出了有名管道。
该管道用于不同进程之间的通信,它提供了一个路径名与之关联,以FIFO的文件形式存在于文件系统
在建立了管道之后,两个进程就可以把它当作普通文件一样进行读写操作,不支持lseek定位操作
要注意的是,有名管道的名字存在于文件系统中,内容放在内存中。
mkfifo f1.pipe

1.有名管道的创建
int mkfifo(const char *pathname, mode_t mode);
pathname:是一个普通的路径名,也就是创建后FIFO文件的名字
mode:与打开普通文件open()函数中的mode参数相同
1.0666,0777,0644...
2.S_IRUSR S_IWGRP S_IXOTH...
返回值:成功返回0
失败返回-1,errno被设置

注:如果mkfifo的第一个参数是个已经存在的路径名时,会返回EEXIST错误
所以,一般最典型的写法是调用代码首先检查是否返回该错误,如果确实返回该错误,那么只需要调用打开FIFO的函数就可以了。

2.有名管道的打开规则:
有名管道比无名管道多了一个打开操作:open()

--------------------------------------
共享内存:
共享内存是以一块内存作为IPC交互的媒介,这块内存由内核维护和管理,允许其它进程映射,共享内存效率是最高的。

1.共享内存的操作流程:
1.创建/获取它共享内存
2.映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问。
3.正常使用
4.解除映射
5.如果确保不再使用,删除共享内存对像

2.相关的API函数
1.shmget函数
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
功能:主要用于创建/获取共享内存段
第一个参数:key,标识共享内存的键值(就像文件的标识是文件名)
第二个参数:要建立的共享内存的长度
第三个参数:有效的标志有IPC_CREAT和IPC_EXCL,与open()函数的O_CREAT与O_EXCL相当。
IPC_CREAT:如果共享内存不存在,则创建一个
IPC_EXCL:与IPC_CREAT搭配使用,如果存在,创建失败

返回值:成功返回一个shmid(类似于打开/创建一个文件获得文件描述符一样)
失败返回-1,errno被设置
注:
当新创建共享内存时,一般情况下第三个参数是:0666 | IPC_CREAT | IPC_EXCL

2.ftok()函数
key_t ftok(const char *pathname, int proj_id);
功能:根据文件路径和项目编号生成key值
第一个参数:字符串形式的文件路径,要求文件必须存在,且可访问。
第二个参数:整型的项目编号,要求必须是非0,低8位被使用,一般写一个字符代替
返回值:成功返回key_t类型的key值
失败返回-1,errno被设置

3.shmat函数
void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:用于映射共享内存到进程的地址空间
第一个参数:shmid,共享内存的ID,shmget()函数的返回值
第二个参数:shmaddr,将共享内存映射到指定的地址,给NULL/0由系统指定
第三个参数:shmflg,默认给0即可,表示共享内存可读可写
返回值:成功返回共享内存的映射地址
失败返回-1,errno被设置

4.shmdt函数
int shmdt(const void *shmaddr);
功能:用于取消共享内存与用户进程的映射
参数:shmaddr:就是shmat的返回值

5.shmctl函数
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:用于对指定的共享内存执行指定的操作
第一个参数:shmid共享内存的ID,即shmget()返回值
第二个参数:cmd,操作命令
IPC_RMID ---删除共享内存,此时第三个参数给NULL即可
第三个参数:buf结构体指针
返回值:成功返回0
失败返回-1,errno被设置

3.相关命令
ipcs -m

-------------------------
消息队列
1.基本概念:
消息队列就是在系统内核中保存的一个用来保存消息的队列,这个队列不是简单的先进先出,还可以控制消息更为灵活。

2.基本通信流程
1.获取key值,使用ftok()函数
2.创建/获取消息队列,使用msgget()函数
3.发送/接收消息,使用msgsnd()函数和msgrcv()函数
4.如果不再使用,删除消息队列,使用msgctl()函数

3.相关API函数
1.msgget()函数
int msgget(key_t key, int msgflg);
功能:主要用于创建/获取消息队列
第一个参数:key,ftok()的返回值
第二个参数:msgflg消息队列的创建标志
IPC_CREAT 创建
IPC_EXCL 与IPC_CREAT搭配使用,若消息队列存在,则创建失败
返回值:成功返回消息队列的ID,失败返回-1,errno被设置
注:
当创建新的消息队列时,需要指定权限,如0644

2.msgsnd()函数
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:主要用于向指定的消息队列发送指定的消息
第一个参数:msqid消息队列的ID,msgget的返回值
第二个参数:msgp消息的首地址
消息的一般形式如下:
struct msgbuf {
long mtype; /* 消息类型, 必须大于0 */
char mtext[1]; /* 消息内容,可以使用其它的数据类型 */
};
第三个参数:msgsz消息的大小,是指定的消息结构体中的内容的大小,不包括消息类型
第四个参数:发送的标志,一般给0即可
返回值:成功返回0,失败返回-1

3.msgrcv()函数
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
功能:主要用于从消息队列中接受消息存到指定的位置
第一个参数:msqid消息队列的ID,msgget的返回值
第二个参数:消息的首地址(表示存到哪里去)
第三个参数:消息的大小
第四个参数:消息的类型
0 ---表示接受消息队列中的第一个消息
>0 ---表示接受消息队列中的第一个类型为msgtyp的消息
<0 ---表示接受消息队列中的第一个小于等于msgtyp绝对值的消息,其中最小的类型优先读取。

第五个参数:接受的标志,一般给0即可
返回值:成功返回实际接受的数据大小,失败返回-1,errno被设置

4.msgctl()函数
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
第一个参数:msqid消息队列的ID,msgget的返回值
第二个参数:cmd操作命令
IPC_RMID 删除消息队列,此时第三个参数给NULL即可。
第三个参数:结构指针

返回值:成功返回0,失败返回-1,errno被设置

4.相关命令
ipcs -q

作业:
1.写一个代码尝试求管道的大小
2.往共享内存中写数据除了memcpy其它的方式
3.写一个程序从消息队列中收消息

/*************************************************************************
> File Name: fifo.c
> Author: csgec
> Mail: longer.zhou@gmail.com
> Created Time: Wed 10 Aug 2016 11:32:55 AM CST
************************************************************************/

#include<stdio.h>
#include<errno.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
int main(int argc,char **argv)
{
int fd;
if(argc < 2)
{
printf("Usage: ./a.out path \n");
exit(-1);
}
if(mkfifo(argv[1],0666) < 0 && errno != EEXIST)
{
perror("mkfifo");
exit(-1);
}
fd = open(argv[1],O_WRONLY);
if(fd < 0)
{
perror("open");
exit(-1);
}
char *str = "hello fifo";
int r = write(fd,str,strlen(str));
printf("r = %d\n",r);
printf("创建FIFO成功\n");

}

/*************************************************************************
> File Name: fifo.c
> Author: csgec
> Mail: longer.zhou@gmail.com
> Created Time: Wed 10 Aug 2016 11:32:55 AM CST
************************************************************************/

#include<stdio.h>
#include<errno.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
int main(int argc,char **argv)
{
int fd;
if(argc < 2)
{
printf("Usage: ./a.out path \n");
exit(-1);
}
if(mkfifo(argv[1],0666) < 0 && errno != EEXIST)
{
perror("mkfifo");
exit(-1);
}
fd = open(argv[1],O_RDONLY);
if(fd < 0)
{
perror("open");
exit(-1);
}
char buf[1024];
int r = read(fd,buf,sizeof(buf));
printf("r = %d\n",r);
printf("读到的内容是:%s\n",buf);

}

/*************************************************************************
> File Name: pipe.c
> Author: csgec
> Mail: longer.zhou@gmail.com
> Created Time: Wed 10 Aug 2016 10:04:54 AM CST
************************************************************************/

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
int main()
{
pid_t pid;
int pipefd[2] = {0};

int res = pipe(pipefd);
char buf[1024] = {0};
if(res == -1)
{
perror("pipe");
exit(-1);
}
printf("fd[0] = %d\n",pipefd[0]);
printf("fd[1] = %d\n",pipefd[1]);

pid = fork();
if(pid < 0)
{
perror("fork");
exit(-1);
}
else if(pid == 0)
{
close(pipefd[1]);

int r = read(pipefd[0],buf,sizeof(buf));
printf("我是子进程,我读到%d个字节,内容是 :%s\n",r,buf);
close(pipefd[0]);
exit(0);
}
else
{
close(pipefd[0]);
char *str = "hello world";
int r = write(pipefd[1],str,strlen(str));
printf("我是父进程,成功写入%d个字节,写入的内容是%s\n",r,str);
close(pipefd[1]);
waitpid(pid,NULL,0);
}

}

#include<stdio.h>
#include<errno.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
int main(int argc,char **argv)
{
int fd;
if(argc < 2)
{
printf("Usage: ./a.out path \n");
exit(-1);
}
if(mkfifo(argv[1],0666) < 0 && errno != EEXIST)
{
perror("mkfifo");
exit(-1);
}
fd = open(argv[1],O_WRONLY);
if(fd < 0)
{
perror("open");
exit(-1);
}
char *str = "hello fifo";
int r = write(fd,str,strlen(str));
printf("r = %d\n",r);
printf("创建FIFO成功\n");

}

pipe管道的更多相关文章

  1. pipe()管道最基本的IPC机制

    <h4>进程间通信 fork pipe pie_t 等用法(管道机制 通信)</h4>每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之 ...

  2. Python第十一天 异常处理 glob模块和shlex模块 打开外部程序和subprocess模块 subprocess类 Pipe管道 operator模块 sorted函数 os模块 hashlib模块 platform模块 csv模块

    Python第十一天    异常处理  glob模块和shlex模块    打开外部程序和subprocess模块  subprocess类  Pipe管道  operator模块   sorted函 ...

  3. python线程,pipe管道通信原理

    Pipe管道: * 管道实例化后会产生两个通道,分别交给两个进程* 通过send和recv来交互数据,这是一个双向的管道,child和parent可以互相收发 from multiprocessing ...

  4. python学习笔记——multiprocessing 多进程组件 Pipe管道

    进程间通信(IPC InterProcess Communication)是值在不同进程间传播或交换信息. IPC通过有管道(无名管道 和 有名 / 命名管道).消息队列.共享存储 / 内容.信号量. ...

  5. Swoole 源码分析——基础模块之 Pipe 管道

    前言 管道是进程间通信 IPC 的最基础的方式,管道有两种类型:命名管道和匿名管道,匿名管道专门用于具有血缘关系的进程之间,完成数据传递,命名管道可以用于任何两个进程之间.swoole 中的管道都是匿 ...

  6. 驱动通信:通过PIPE管道与内核层通信

    在本人前一篇博文<驱动开发:通过ReadFile与内核层通信>详细介绍了如何使用应用层ReadFile系列函数实现内核通信,本篇将继续延申这个知识点,介绍利用PIPE命名管道实现应用层与内 ...

  7. Linux中的pipe(管道)与named pipe(FIFO 命名管道)

    catalogue . pipe匿名管道 . named pipe(FIFO)有名管道 1. pipe匿名管道 管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入,常 ...

  8. ionic3中创建pipe管道

    1.使用ionic cli创建pipe管道文件 ionic g pipe parse-date 该命令会在src文件夹创建pipes/parse-date/parse-date.ts文件,并且会在pi ...

  9. angular2+ 自定义pipe管道实例--定义全局管道及使用

    首先到项目目录下ng g pipe pipe/myslice 就会在app目录下生成一个pipe文件夹文件夹下有myslice.pipe.ts文件,如果没有也可以自己手动新建 然后需要再app.mod ...

随机推荐

  1. 风格一致的backItem在项目中怎样设置

    在相应的navigationController中重写- (void)pushViewController:(UIViewController *)viewController animated:(B ...

  2. (转)mahout中k-means例子的运行

           首先简单说明下,mahout下处理的文件必须是SequenceFile格式的,所以需要把txtfile转换成sequenceFile.SequenceFile是hadoop中的一个类,允 ...

  3. Android------>TableLayout表格布局方式

    main.xml表格代码分析 <?xml version="1.0" encoding="utf-8"?> <TableLayout xmln ...

  4. c#获取新浪微博登录cookie

    用新浪微博api收集数据有诸多限制,每小时只能调用官方api函数150次,认证也很麻烦.因此想通过爬网页的方式来收集数据.访问新浪微博用户网页首先需要登录,登录获取cookie后可直接获取网页数据,无 ...

  5. glibc

    http://www.cnblogs.com/vipzrx/p/3599506.html 原因 wheezy是2.13,编译android4.4 需要2.14的,报错如下: rebuilts/gcc/ ...

  6. 打开地图文件和shape文件代码加载Mxd文档

    代码加载Mxd文档 用代码添加Mxd文档,用到AxMapControl.LoadMxFile(sFilePath),我们只要将Mxd文档的路径传给这个方法即可 /// <summary>  ...

  7. Js实例——模态框弹出层

    1.描述 百度登录就是一个模态框弹出层.思路分析:先将灰色大背景和登陆盒子设为不可见,利用JS将其动态加载可见. 2.代码 <!DOCTYPE html> <html> < ...

  8. MAC 调整Launchpad 图标大小

    1.调整每一列显示图标数量 defaults write com.apple.dock springboard-rows -int 7 2.调整每一行显示图标数量 defaults write com ...

  9. iOS AFN向接口端传递JSON数据

    NSDictionary *body = @{@"snippet": @{@"topLevelComment":@{@"snippet":@ ...

  10. windows下 nginx php 环境搭建

    windows下配置nginx+php环境 刚看到nginx这个词,我很好奇它的读法(engine x),我的直译是“引擎x”,一般引“擎代”表了性能,而“x”大多出现是表示“xtras(额外的效果) ...