一 分类
1.同一主机
(1)传统
无名管道;
有名管道;
信号。
(2)SystemV
共享内存;//这是效率最高的通信方式
消息队列;
信号量。//都是信号量的机制
2.不同主机
socket:分为本地socket(本地套接字)和不同主机socket(网络套接字)。
二 原理
每个进程都拥有独立的4G内存空间,但其中的内核(1G)空间是共享的,所有进程间的通信方式,本质上都是借助操作系统内核来完成的。
三 无名管道
就是在内核建立一个管道,无名管道本质上是一种特殊的文件,它不存在硬盘,而是在内核空间的内存中,因为在文件系统中没有名字,所以叫无名。
1.无名管道的创建
int pipe(int pipefd2);
参数:pipefd,用来存放管道两端的文件描述符,0是读端,1是写端
返回值:成功返回0,失败返回-1并且errno会被设置
2.管道的特点
1)管道的大小---64kb(65526个字节)
2)管道读写规则
读写端都存在,可以读写管道,但是如果管道是满的,写操作阻塞,如果管道是空的,读操作会阻塞;读端存在写端不存在,如果管道是空的,读操作直接返回;读端不存在写端存在,如果进行写操作,管道破裂(SIGPIPE --- 信号的作用 --结束进程 //broken pipe )。
3.管道中的数据
是一个数据流,读走了就没有了,遵循FIFO的方式
4.是一种特殊的文件,但是不能进行lseek操作(插队)
5.用在亲缘关系进程间通信
6.管道是一种半双工的通信
单工:数据的发送方和接收方是固定的eg:广播
半双工:同一时刻只能有一个方向的数据传输eg:对讲机
全双工:同时收同时发
无名管道实际上是单工的,但是可以实现半双工的效果。
创建管道进行读写:
cpp
#include<stdio.h>
#include<unistd.h>
int main(int argc, const char *argv[])
{
int fd[2];
if(pipe(fd) < 0)
{
perror("pipe fail");
return -1;
}
printf("fd[0] = %d fd[1] = %d\n",fd[0],fd[1]);
char buf[]="abcdefg";
int ret_w = write(fd[1],buf,sizeof(buf));
int ret_r = read(fd[0],buf,sizeof(buf));
printf("ret_w = %d ret_r = %d\n",ret_w,ret_r);
return 0;
}
父进程写管道数据,子进程读管道数据:
cpp
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<string.h>
int main(int argc, const char *argv[])
{
int fd[2];
if(pipe(fd) < 0)
{
perror("pipe fail");
return -1;
}
pid_t pid = fork();
if(pid < 0)
{
perror("fork fail");
return -1;
}
if(pid>0)
{
close(fd[0]);
while(1)
{
char buf[1024];
fgets(buf,sizeof(buf),stdin);
write(fd[1],buf,sizeof(buf));
if(strncmp(buf,"quit",4) == 0)
{
close(fd[1]);
wait(NULL);
exit(0);
}
}
}else if(pid == 0)
{
close(fd[1]);
while(1)
{
char buf[1024];
read(fd[0],buf,sizeof(buf));
printf("%s\n",buf);
if(strncmp(buf,"quit",4)==0)
{
close(fd[0]);
exit(0);
}
}
}
return 0;
}
父子进程双向通信
cpp
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<string.h>
int main(int argc, const char *argv[])
{
int fd[2];
if(pipe(fd) < 0)
{
perror("pipe fail");
return -1;
}
int fd1[2];
if(pipe(fd1) < 0)
{
perror("pipe fail");
return -1;
}
pid_t pid = fork();
if(pid < 0)
{
perror("fork fail");
return -1;
}
if(pid>0)
{
close(fd[0]);
close(fd1[1]);
while(1)
{
char buf[1024];
printf("input 1 pipe:");
fgets(buf,sizeof(buf),stdin);
write(fd[1],buf,sizeof(buf));
char buf1[1024];
read(fd1[0],buf1,sizeof(buf1));
printf("pipe 2 = %s\n",buf1);
if(strncmp(buf,"quit",4) == 0 || strncmp(buf1,"quit",4) == 0)
{
close(fd1[0]);
close(fd[1]);
wait(NULL);
exit(0);
}
}
}else if(pid == 0)
{
close(fd[1]);
close(fd1[0]);
while(1)
{
char buf[1024];
read(fd[0],buf,sizeof(buf));
printf("pipe 1 = %s\n",buf);
char buf1[1024];
printf("input 2 pipe:");
fgets(buf1,sizeof(buf1),stdin);
write(fd1[1],buf1,sizeof(buf1));
if(strncmp(buf,"quit",4)==0 || strncmp(buf1,"quit",4)==0)
{
close(fd[0]);
close(fd1[1]);
exit(0);
}
}
}
return 0;
}
四 有名管道
- 特点:
符合管道特性;有名管道也是一种特殊的文件,有名 --- 在文件系统有名字类似于普通文件的名字,使用时,可以当作普通文件进行操作但也不能lseek 定位
2.用途:任意进程间
3.创建
int mkfifo(const char *pathname, mode_t mode);
功能:创建有名管道文件
参数:pathname----管道文件名;mode---文件权限
返回值:成功 0,失败 -1 && errno被设置
有名管道进行通信时,需要进行打开操作 open,如果只有一端 以 只读或只写的方式打开 ,此时程序会阻塞在open操作 ,必须等待 另一端 以只写或只读的相对方式打开,阻塞才会解除,此时也表示有名管道文件 读端和写端都打开了。
4.卸载管道:
int unlink(const char *pathname);
功能:将指定的pathname管道文件卸载,同时从文件系统中删除。
参数: ptahtname 要卸载的有名管道
返回值:成功 0,失败 -1;
创建管道进行读写:
cpp
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
int main(int argc, const char *argv[])
{
if(mkfifo("fifo",0666) < 0 && errno != EEXIST)
{
perror("mkfifo fail");
return -1;
}
printf("mkfifo success\n");
int fd = open("fifo",O_RDONLY);
if(fd < 0)
{
perror("open fail");
return -1;
}
while(1)
{
char buf[1024];
read(fd,buf,sizeof(buf));
printf("%s\n",buf);
if(strncmp(buf,"quit",4)==0)
{
break;
}
}
close(fd);
unlink("fifo");
return 0;
}
cpp
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>
int main(int argc, const char *argv[])
{
if(mkfifo("fifo",0666) < 0 && errno != EEXIST)
{
perror("mkfifo fail");
return -1;
}
printf("mkfifo success\n");
int fd = open("fifo",O_WRONLY);
if(fd < 0)
{
perror("open fail");
return -1;
}
while(1)
{
char buf[1024];
printf("Input > ");
fgets(buf,sizeof(buf),stdin);
write(fd,buf,sizeof(buf));
if(strncmp(buf,"quit",4)==0)
{
break;
}
}
close(fd);
unlink("fifo");
return 0;
}
双向通信:两边同时收和发
cpp
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
int main(int argc, const char *argv[])
{
if(mkfifo("fifo1",0666) < 0 && errno != EEXIST)
{
perror("mkfifo fail");
return -1;
}
printf("mkfifo1 success\n");
int fd1 = open("fifo1",O_RDONLY);
if(fd1 < 0)
{
perror("open fail");
return -1;
}
if(mkfifo("fifo2",0666) < 0 && errno != EEXIST)
{
perror("mkfifo fail");
return -1;
}
printf("mkfifo1 success\n");
int fd2 = open("fifo2",O_WRONLY);
if(fd2 < 0)
{
perror("open fail");
return -1;
}
pid_t pid = fork();
if(pid > 0)
{
while(1)
{
sleep(1);
char buf[1024];
printf("2 fifo Input>");
fgets(buf,sizeof(buf),stdin);
write(fd2,buf,sizeof(buf));
if(strncmp(buf,"quit",4)==0)
{
break;
}
}
}else if(pid == 0)
{
while(1)
{
sleep(1);
char buf[1024];
read(fd1,buf,sizeof(buf));
printf("1 fifo output = %s\n",buf);
if(strncmp(buf,"quit",4)==0)
{
break;
}
}
}
close(fd1);
close(fd2);
unlink("fifo1");
unlink("fifo2");
return 0;
}
cpp
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
int main(int argc, const char *argv[])
{
if(mkfifo("fifo1",0666) < 0 && errno != EEXIST)
{
perror("mkfifo fail");
return -1;
}
printf("mkfifo1 success\n");
int fd1 = open("fifo1",O_WRONLY);
if(fd1 < 0)
{
perror("open fail");
return -1;
}
if(mkfifo("fifo2",0666) < 0 && errno != EEXIST)
{
perror("mkfifo fail");
return -1;
}
printf("mkfifo1 success\n");
int fd2 = open("fifo2",O_RDONLY);
if(fd2 < 0)
{
perror("open fail");
return -1;
}
pid_t pid = fork();
if(pid > 0)
{
while(1)
{
sleep(1);
char buf[1024];
printf("1 fifo input>");
fgets(buf,sizeof(buf),stdin);
write(fd1,buf,sizeof(buf));
if(strncmp(buf,"quit",4)==0)
{
break;
}
}
}else if(pid == 0)
{
while(1)
{
sleep(1);
char buf[1024];
read(fd2,buf,sizeof(buf));
printf("2 fifo out %s\n",buf);
if(strncmp(buf,"quit",4)==0)
{
break;
}
}
}
close(fd1);
close(fd2);
unlink("fifo1");
unlink("fifo2");
return 0;
}