网站上做网上支付功能,临沂做企业网站,wordpress建立个人网站,网站制作论文总结文章目录 进程间通信1.进程间通信的介绍1.1目的和发展 2.进程间通信分类3.管道3.1匿名管道3.1.1匿名管道的原理#xff08;文件角度#xff09;3.1.2匿名管道的原理#xff08;内核角度#xff09;3.1.3管道读写规则3.1.4管道特点 3.2命名管道3.2.1创建命名管道3.2.2命名管… 文章目录 进程间通信1.进程间通信的介绍1.1目的和发展 2.进程间通信分类3.管道3.1匿名管道3.1.1匿名管道的原理文件角度3.1.2匿名管道的原理内核角度3.1.3管道读写规则3.1.4管道特点 3.2命名管道3.2.1创建命名管道3.2.2命名管道的打开规则 4.命名管道实现serverclient通信 进程间通信
1.进程间通信的介绍 进程间通信IPCInterprocess communication是一组编程接口让程序员能够协调不同的进程使之能在一个操作系统里同时运行并相互传递、交换信息。这使得一个程序能够在同一时间里处理许多用户的要求。因为即使只有一个用户发出要求也可能导致一个操作系统中多个进程的产生。进程间通信可以发生在同一台机器上的不同进程间也可以发生在不同机器上的进程间。
1.1目的和发展 目的 1数据传输一个进程需要将它的数据发送给另一个进程。 2资源共享多个进程之间共享同样的资源。 3通知事件一个进程需要向另一个或一组进程发送消息通知它它们发生了某种事件如进程终止时要通知父进程。 4进程控制有些进程希望完全控制另一个进程的执行如Debug进程此时控制进程希望能够拦截另一个进程的所有陷入和异常并能够及时知道它的状态改变。 发展 管道 - System V进程间通信 - POSIX进程间通信。
2.进程间通信分类 管道匿名管道、命名管道 System V IPCSystem V 消息队列、System V 共享内存、System V 信号量 POSIX IPC消息队列、共享内存、信号量、互斥量、条件变量、读写锁
3.管道 管道是Unix中最古老的进程间通信的形式。我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”。
3.1匿名管道 匿名管道的原理: 匿名管道的原理是使用pipe函数创建管道并在父进程中得到两个文件描述符一个用于从管道读数据另一个用于向管道写数据。 子进程在创建时会自动继承这两个文件描述符从而可以实现父子进程间的数据交换。
#include unistd.h//功能:创建一无名管道//原型
int pipe(int fd[2]);//参数
//fd文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
//返回值:成功返回0失败返回错误代码//例子从键盘读取数据写入管道读取管道写到屏幕
#include stdio.h
#include stdlib.h
#include string.h
#include unistd.h
int main( void )
{int fds[2];char buf[100];int len;if ( pipe(fds) -1 )perror(make pipe),exit(1);// read from stdinwhile ( fgets(buf, 100, stdin) ) {len strlen(buf);// write into pipeif ( write(fds[1], buf, len) ! len ){perror(write to pipe);break;}memset(buf, 0x00, sizeof(buf));// read from pipeif ( (lenread(fds[0], buf, 100)) -1 ) {perror(read from pipe);break;}// write to stdoutif ( write(1, buf, len) ! len ) {perror(write to stdout);break;}}
}3.1.1匿名管道的原理文件角度 匿名管道的原理从文件角度来说是利用内存中共享的一段缓冲区以文件的方式对缓冲区实现。但因为该文件只存在于内存中没有唯一命名所以称为匿名管道。 具体来说父进程创建管道文件描述符然后通过fork创建子进程。子进程继承了父进程的文件描述符这样父子进程就可以通过这个文件描述符进行通信。 由于管道是半双工方式数据传输的方向是单向的所以如果需要进行双向通信需要创建两个管道。 3.1.2匿名管道的原理内核角度 从内核角度来说匿名管道的原理是利用内核缓冲区作为伪文件这个缓冲区由读端和写端两部分组成对应两个文件描述符。数据从写端流入从读端流出。 匿名管道的内部实现方式是队列而且是环形队列。这种队列的特性是先进先出即一端入队另一端出队即只能从一端写入另一端读出。缓冲区的大小默认是4k字节但会根据实际情况做适当调整。 由于用队列实现数据只能读取一次不能重复读取。另外匿名管道是半双工方式数据传输的方向是单向的。此外匿名管道只适用于有血缘关系的进程如父子进程、兄弟进程等。 这也符合了Linux的一切皆文件的思想 父进程tast_struct中有指向file_struct的指针 *file其中files_struct是一个struct file *fd_array[]这个array的数组中指向了各种的文件。同时创建子进程子进程是父进程的一份拷贝所以此时父进程指向的文件子进程也同样会指向该文件进程间通信的前提完成让不同的文件看到同一份资源。 接着我们可以进行不同进程间的通信了如果我们想要先让子进程写入父进程读取。则我们可以在父进程和子进程所指的同一个文件中进行不同的操作让子进程在文件缓冲区中写入数据让父进程在同样的文件缓冲区中读取数据。即可完成通过使用管道的通信操作所以管道也是文件。 3.1.3管道读写规则 1当没有数据可读时 O_NONBLOCK disableread调用阻塞即进程暂停执行一直等到有数据来到为止。 O_NONBLOCK enableread调用返回-1errno值为EAGAIN。 2当管道满的时候 O_NONBLOCK disable write调用阻塞直到有进程读走数据。 O_NONBLOCK enable调用返回-1errno值为EAGAIN。 3如果所有管道写端对应的文件描述符被关闭 则read返回0。 4如果所有管道读端对应的文件描述符被关闭 则write操作会产生信号SIGPIPE,进而可能导致write进程退出。 5当要写入的数据量不大于PIPE_BUF时linux将保证写入的原子性。 6当要写入的数据量大于PIPE_BUF时linux将不再保证写入的原子性。 3.1.4管道特点 1只能用于具有共同祖先的进程具有亲缘关系的进程之间进行通信 通常一个管道由一个进程创建然后该进程调用fork此后父、子进程之间就可应用该管道。 2管道提供流式服务。 3一般而言进程退出管道释放所以管道的生命周期随进程。 4一般而言内核会对管道操作进行同步与互斥。 5管道是半双工的数据只能向一个方向流动 需要双方通信时需要建立起两个管道。 3.2命名管道 命名管道的介绍 Linux命名管道是一种特殊的文件类型它允许不具有亲缘关系的进程之间进行通信。命名管道存在于文件系统中但同时具有管道的优点可以用于进程间通信。进程通过操作命名管道文件进行数据交换。 命名管道的创建可以使用命令行工具如mkfifo命令或者在编程语言中的调用系统调用接口如mkfifo函数来创建。 创建好命名管道之后可以使用open()和read/write()函数来读取和写入数据。 在数据传输方面命名管道的数据传输不会写入磁盘而是在内存中进行传递。命名管道允许多个进程通过使用相同的管道名称进行通信而不仅仅是两个进程之间的通信。与普通管道一样命名管道中的数据也是临时存储在内存中的。 3.2.1创建命名管道 命名管道可以从命令行上创建
$ mkfifo filename命名管道也可以从程序里创建相关函数有
int mkfifo(const char *filename,mode_t mode);创建命名管道:
int main(int argc, char *argv[])
{mkfifo(p2, 0644);return 0;
}匿名管道与命名管道的区别 1匿名管道由pipe函数创建并打开。 2命名管道由mkfifo函数创建打开用open。 3FIFO命名管道与pipe匿名管道之间唯一的区别在它们创建与打开的方式不同一但这些工作完成之后它们具有相同的语义。 3.2.2命名管道的打开规则 1如果当前打开操作是为读而打开FIFO时 O_NONBLOCK disable阻塞直到有相应进程为写而打开该FIFO。 O_NONBLOCK enable立刻返回成功。 2如果当前打开操作是为写而打开FIFO时 O_NONBLOCK disable阻塞直到有相应进程为读而打开该FIFO。 O_NONBLOCK enable立刻返回失败错误码为ENXIO。 4.命名管道实现serverclient通信
测试实现 comm.hpp
#pragma once#includeiostream
#includesys/types.h
#includesys/stat.h
#includecerrno
#includestring
#include unistd.h
#include fcntl.h#define FIFO_FILE ./myfifo
#define MODE 0664enum{FIFO_CREATE_ERR1,FIFO_DELETE_ERR2,FIFO_OPEN_ERR3
};Makefile
.PHONY:all
all:server client
server:server.ccg -o $ $^ -stdc11
client:client.ccg -o $ $^ -stdc11
.PHONY:clean
clean:rm -f client server myfifoserver.cc
//#includeiostream
#includecomm.hppusing namespace std;//管理管道文件
int main()
{//创建信道int nmkfifo(FIFO_FILE,MODE);if(n-1){perror(mkfifo);exit(FIFO_CREATE_ERR);}//sleep(5);//打开信道int fdopen(FIFO_FILE,O_RDONLY);if(fd0){perror(open);exit(FIFO_OPEN_ERR);}coutserver open file doneendl;//开始信道while(true){char buffer[1024]{0};int xread(fd,buffer,sizeof(buffer));if(x0){buffer[x]0;coutclient say#bufferendl;}else if(x0){coutclinet quit,me too!\nendl;break;} else break;}close(fd);int munlink(FIFO_FILE);if(m-1){perror(unlink);exit(FIFO_DELETE_ERR);}return 0;
}client.cc
#includeiostream
#includecomm.hppusing namespace std;int main()
{int fdopen(FIFO_FILE,O_WRONLY);if(fd0){perror(open);exit(FIFO_OPEN_ERR);}string line;while(true){coutPlease Enter;//cinline;getline(cin,line);write(fd,line.c_str(),line.size());}close(fd);return 0;
}