linux学习---linux基于文件的IPC(匿名管道pipe,命名管道mkfifo,普通文件,socket文件)
来源:互联网 发布:中国质造 淘宝 编辑:程序博客网 时间:2024/05/19 05:41
常用的IPC分为两个类别,一是基于文件,而是基于内存
基于文件的分别有匿名管道,有名管道,普通的文件共享,socket文件
基于内存的有普通内存共享(本文章没有介绍),共享内存,共享信号量,消息队列
如果要看基于内存的IPC,请参考:http://blog.csdn.net/xiaoxiaopengbo/article/details/78431042
本文就针对linux基于文件的IPC
一.匿名管道pipe
管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。有如下特质:
1. 其本质是一个伪文件(实为内核缓冲区)
2. 由两个文件描述符引用,一个表示读端,一个表示写端。
3. 规定数据从管道的写端流入管道,从读端流出。
管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。
管道的局限性:
1) 数据一旦被读走,便不在管道中存在,不可反复读取。
2) 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。
3)只能在有公共祖先的进程间使用管道。
常见的通信方式有,单工通信、半双工通信、全双工通信。
函数原形
#include <unistd.h>
int pipe(int pipefd[2]);
返回值 成功:0;失败:-1,设置errno
Pipefd参数是一个入参,函数调用成功返回r/w两个文件描述符。无需open,但需手动close。规定:fd[0]→ r; fd[1] → w,就像0对应标准输入,1对应标准输出一样。向管道文件读写数据其实是在读写内核缓冲区。
有记下几种编程模型:单进程半双工,父子进程半双工
下图是单进程的半双工编程模型,并附带程序源码
#include <stdio.h>#include <stdlib.h>#include <unistd.h>int main(){ intfd[2]; intr; charbuf[40]; printf("%d\n",getpid()); r=pipe(fd); write(fd[1],"hello",5); write(fd[1],"world",5); r=read(fd[0],buf,20); buf[r]=0; printf("1::%s\n",buf); write(fd[1],"Iam writing to pipe",strlen("I am writing to pipe")); r=read(fd[0],buf,20); buf[r]=0; printf("2::%s\n",buf); r=read(fd[0],buf,20); buf[r]=0; printf("3::%s\n",buf); while(1);}
执行结果
结论:此程序证明了第一点局限数据一旦被读走,便不在管道中存在,不可反复读取。但是这种编程模型基本没有用途
下面来看看另外一种编程模型,父子进程之前的半双工,同样源码如下
#include <stdio.h>#include <stdlib.h>#include <unistd.h> int main(void){ int n; int fd[2]; pid_t pid; char line[20]={0}; if(pipe(fd) < 0) printf("pipeerr:%m\n"); if((pid = fork()) < 0) { printf("forkerr:%m\n"); }else if (pid > 0) { /* parent */ close(fd[0]); write(fd[1],"hello world\n", 12); }else { /* child */ close(fd[1]); n= read(fd[0], line, 20); printf("%s\n",line); } exit(0);}
运行结果
二.有名管道FIFO
上面的匿名管道的缺点其实是很明显的,虽然可以进程间通信,但是只局限于有血缘关系的进程间通信,但是如果我想两个独立的进程用管道来通信呢?有名管道FIFO就有了用武的地方了
创建有名管道函数原形
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_tmode);
返回值
返回值 成功:0;失败:-1,设置errno
程序源码,创建两个文件fifoA.c fifoB.c分别编译为A,B
fifoA.c
#include <stdio.h>#include <fcntl.h>#include <unistd.h>#include <sys/stat.h>#include <signal.h>#include <stdlib.h>int fd;int i=0;void end(int s){ printf("catchctrl+c signal\n"); //closepipe close(fd); //deletepipe unlink("my.pipe"); exit(-1);}int main(){ signal(SIGINT,end); //createpipe file mkfifo("my.pipe",0666); //openpipe file fd=open("my.pipe",O_RDWR); //writedata per 1 sec while(1) { sleep(1); write(fd,&i,4); i++; } }
fifoB.c
#include <stdio.h>#include <fcntl.h>#include <unistd.h>#include <sys/stat.h>#include <signal.h>#include <stdlib.h>int fd;int i;void end(int s){ printf("catchctrl+c signal\n"); //closepipe close(fd); exit(-1); }int main(){ signal(SIGINT,end); //openpipe file fd=open("my.pipe",O_RDWR); //readdata while(1) { read(fd,&i,4); printf("%d\n",i); }}
先运行fifoA.c的程序,发现就会创建一个
此时运行B程序,发现数据并没有丢失,一下会把之前的都打印出来
另外需要注意的是:FIFO和pipe一样,数据不会重复读出
三.基于文件共享的IPC
源码:
分别有procA.c procB.c,分别编译成A,B可以执行程序
ProcA.c
#include <stdio.h>#include <fcntl.h>#include <sys/mman.h>main(){ int*p; intfd; inti; fd=open("tmp",O_RDWR|O_CREAT,0666); ftruncate(fd,4); p=mmap(0,4,PROT_READ|PROT_WRITE, MAP_SHARED,fd,0); i=0; while(1) { sleep(1); *p=i; i++; } close(fd);}
ProcB.c
#include <stdio.h>#include <fcntl.h>e#include <sys/mman.h>main(){ int*p; intfd; fd=open("tmp",O_RDWR); p=mmap(0,4,PROT_READ|PROT_WRITE, MAP_SHARED,fd,0); while(1) { sleep(1); printf("%d\n",*p); } close(fd);}
运行结果
A程序每隔1s写一次数,写的数每次+1
运行B程序如图
发现还是结果会丢失的
四.socket文件的IPC
socket网络编程可能使用得最多,经常用在网络上不同主机之间的通信。其实在同一主机内通信也可以使用socket来完成,socket进程通信与网络通信使用的是统一套接口,只是地址结构与某些参数不同。在使用socket创建套接字时通过指定参数domain是af_inet(ipv4因特网域)或af_inet6(ipv6因特网域)或af_unix(unix域)来实现。
函数原形
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, intprotocol);
第一个参数demain是协议簇
Name Purpose Man page
AF_UNIX, AF_LOCAL Local communication unix(7)
AF_INET IPv4 Internet protocols ip(7)
AF_INET6 IPv6 Internet protocols ipv6(7)
AF_IPX IPX - Novell protocols
AF_NETLINK Kernel user interface device netlink(7)
AF_X25 ITU-T X.25 / ISO-8208protocol x25(7)
AF_AX25 Amateur radio AX.25 protocol
AF_ATMPVC Access to raw ATM PVCs
AF_APPLETALK Appletalk ddp(7)
AF_PACKET Low level packet interface packet(7)
一般常用的就是前三个
Type参数有以下几个选择
SOCK_STREAM Provides sequenced, reliable, two-way,connection-based
byte streams. An out-of-band data transmission mecha‐
nism may be supported.
SOCK_DGRAM Supports datagrams (connectionless,unreliable messages
of a fixed maximumlength).
SOCK_SEQPACKET Provides a sequenced, reliable, two-way connection-
based data transmissionpath for datagrams of fixed
maximum length; a consumer is required to read anentire packet with each input system call.
SOCK_RAW Provides raw network protocol access.
SOCK_RDM Provides a reliable datagram layer thatdoes not guar‐antee ordering.
SOCK_PACKET Obsolete and should not be used in new programs; see packet(7).
第三个参数很少用,一般通过前两个参数就能确定要传输的协议,我通常都设为0
返回值 成功:返回文件描述符;失败:-1,设置errno
直接贴两个进程间通讯的
socketA.c socketB.c
socketA.c
#include <sys/socket.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <linux/un.h> int main(){ intfd; intr; charbuf[200]; //1.建立socket fd=socket(AF_UNIX,SOCK_DGRAM,0); if(fd==-1)printf("socketerr:%m\n"),exit(-1); printf("socket成功\n"); //2.构造本地文件地址 structsockaddr_un addr={0}; addr.sun_family=AF_UNIX; memcpy(addr.sun_path,"my.sock",strlen("my.sock")); //3.把socket绑定在地址上 r=bind(fd,(structsockaddr*)&addr,sizeof(addr)); if(r==-1)printf("binderr:%m\n"),exit(-1); printf("地址绑定成功\n"); //4.接受数据 bzero(buf,sizeof(buf)); r=read(fd,buf,sizeof(buf)); printf("%s\n",buf); //5.关闭通道 close(fd); //6.删除socket文件 unlink("my.sock");}
socketB.c
#include <sys/socket.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <linux/un.h> int main(){ intfd; intr; charbuf[200]; structsockaddr_un addr={0}; //1.建立socket fd=socket(AF_UNIX,SOCK_DGRAM,0); if(fd==-1)printf("socketerr:%m\n"),exit(-1); printf("socket成功\n"); //2.链接到指定地址 addr.sun_family=AF_UNIX; memcpy(addr.sun_path,"my.sock",strlen("my.sock")); r=connect(fd,(structsockaddr*)&addr,sizeof(addr)); if(r==-1)printf("binderr:%m\n"),exit(-1); printf("地址连接成功\n"); //3.发送数据 write(fd,"hello!",strlen("hello")); //4.关闭通道 close(fd);}
运行结果
下面举一个网络通信的socket,编程模型是一致的,ipA.c ipB.c
ipA.c
#include <sys/socket.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <linux/un.h>#include <netinet/in.h>#include <arpa/inet.h>int main(){ intfd; intr; charbuf[200]; //1.建立socket fd=socket(AF_INET,SOCK_DGRAM,0); if(fd==-1)printf("socketerr:%m\n"),exit(-1); printf("socket成功\n"); //2.构造本地文件地址 structsockaddr_in addr={0}; addr.sin_family=AF_INET; addr.sin_port=htons(9999); addr.sin_addr.s_addr=inet_addr("192.168.1.102"); //3.把socket绑定在地址上 r=bind(fd,(structsockaddr*)&addr,sizeof(addr)); if(r==-1)printf("binderr:%m\n"),exit(-1); printf("地址绑定成功\n"); //4.接受数据 bzero(buf,sizeof(buf)); r=read(fd,buf,sizeof(buf)); printf("%s\n",buf); //5.关闭通道 close(fd); //6.删除socket文件 }ipB.c
#include <sys/socket.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <linux/un.h>#include <netinet/in.h>#include <arpa/inet.h>int main(){ intfd; intr; charbuf[200]; //1.建立socket fd=socket(AF_INET,SOCK_DGRAM,0); if(fd==-1)printf("socketerr:%m\n"),exit(-1); printf("socket成功\n"); //2.构造本地文件地址 structsockaddr_in addr={0}; addr.sin_family=AF_INET; addr.sin_port=htons(9999); addr.sin_addr.s_addr=inet_addr("192.168.1.102"); //3.把socket绑定在地址上 r=connect(fd,(structsockaddr*)&addr,sizeof(addr)); if(r==-1)printf("binderr:%m\n"),exit(-1); printf("地址绑定成功\n"); //4.接受数据 write(fd,"hello!",strlen("hello")); //5.关闭通道 close(fd); //6.删除socket文件}
运行结果是和上面的类似的
- linux学习---linux基于文件的IPC(匿名管道pipe,命名管道mkfifo,普通文件,socket文件)
- Linux c 管道文件-进程间的通信 mkfifo、pipe
- Linux——IPC 基于文件的通信(普通文件 管道文件)
- linux c学习笔记----管道文件(pipe,popen,mkfifo,pclose,dup2)
- Linux进程间的通信-基于有序文件(匿名管道)
- 【linux】匿名管道pipe
- 【Linux/OS/Network】匿名管道(pipe)和命名管道(FIFO)
- Linux系统编程之管道:匿名管道pipe与命名管道fifo
- linux系统编程之管道(一):匿名管道(pipe)
- linux系统编程之管道(一):匿名管道(pipe)
- 【Linux】进程间通信(IPC)之匿名管道和命名管道以及测试用例
- linux ipc之匿名管道
- 【编撰】linux IPC 002 - 匿名管道PIPE和有名管道FIFO的概念和实例,以及应用比较
- Linux系统常用指令、管道(pipe)、文件查找(find)
- Linux 管道文件
- Linux 管道(pipe)
- linux中匿名管道和命名管道
- linux中的匿名管道和命名管道
- java 10.28/29
- 【数论】求逆元
- 欢迎使用CSDN-markdown编辑器
- C++三种class constructors
- Navi.Soft31.WinForm框架(含下载地址)
- linux学习---linux基于文件的IPC(匿名管道pipe,命名管道mkfifo,普通文件,socket文件)
- 终于!TensorFlow引入了动态图机制Eager Execution
- 用100元的支票骗到100万:看看对抗性攻击是怎么为非作歹的
- 数据结构之线索二叉树数据结构
- GANs正在多个层面有所突破
- 【数论】【中国剩余定理】解线性模方程
- 560万Facebook人际关系数据,揭秘家庭职业传承“真相”
- 虚构的对抗:GAN with the wind
- 用公开语料推进NLP研究,孵化现象级产品 | 专访阿里AI Labs聂再清