linux连续管道,linux之管道

1. 进程间通信概述

进程是一个独立的资源分配单元,不同进程之间的资源是独立的,没有关联,不能在一个进程中直接访问另一个进程的资源。进程不是孤立的,不同的进程需要进行信息的交互和状态的传递等,因此需要进程间通信。

1.1 进程间通信功能

(1)数据传输:一个进程需要将它的数据发送给另一个进程。

(2)资源共享:多个进程之间共享同样的资源。

(3)通知事件:一个进程需要向另一个或一组进程发送消息,通知它们发生了某种事件。

(4)进程控制:有些进程希望完全控制另一个进程的执行,此时控制进程希望能够拦截另一个进程的所有操作,并能够及时知道它的状态改变

1.2 主要进程间通信的通信机制

1f3eeb6b018c86a140c4dee5b986a089.png

2. 管道

2.1 管道特点

管道(pipe)又称无名管道,是一种特殊类型的文件,在应用层体现为两个打开的文件描述符

bf1eb4581add403f68ccf4652c97eb6a.png

(1)半双工,数据在同一时刻只能在一个方向上流动

(2)管道不是普通的文件,不属于某个文件系统,其只存在于内存中

(3)管道没有名字,只能在具有公共祖先的进程之间使用

(4)管道的缓冲区大小是有限的,在linux中,该缓冲区的大小固定为4k

2.2 管道数据传输

9388f918c05fb95f79ff12f33b7c38d8.png

2.3 函数

#include

int pipe(int filedes[2]);

功能:经由参数filedes返回两个文件描述符

参数:

filedes为int型数组的首地址,其存放了管道的文件描述符fd[0]、fd[1]。

filedes[0]为读而打开,filedes[1]为写而打开

管道,filedes[0]的输出是filedes[1]的输入。

返回值:成功:返回0失败:返回-1

2.4 例子

#include "intf.h"#include#include

using namespacestd;#define BUFFSIZE 1024

int main(int argc, char *argv[])

{int ParentFd[2];

cout<< "程序开始" <

{

perror("创建管道失败");

}

printf("创建管道成功");int pid =fork();if(pid < 0)

{

perror("创建进程失败");

}else if(pid == 0)

{

printf("子进程:");

close(ParentFd[0]);

cout<< "请输入要写入的字符" <

{

write(ParentFd[1], s.c_str(), s.length());if(s == "quit")

{

exit(0);

}

}

}else{

cout<< "父进程:" <

close(ParentFd[1]);while(1)

{char msg[BUFFSIZE] = {0};

read(ParentFd[0], msg, BUFFSIZE);

cout<< "父进程显示:" << msg <

{

exit(0);

}

}

}

cout<< "程序结束" <

}

3. 命名管道

命名管道(FIFO)和管道(PIPE)基本相同,FOFO有名字,不同的进程可以通过该命名管道进行通信

3.1 函数介绍

(1)access

access():判断是否具有存取文件的权限

相关函数    stat,open,chmod,chown,setuid,setgid

表头文件    #include定义函数    int access(const char * pathname, int mode);函数说明    access()会检查是否可以读/写某一已存在的文件。参数mode有几种情况组合, R_OK,W_OK,X_OK 和F_OK。R_OK,W_OK与X_OK用来检查文件是否具有读取、写入和执行的权限。F_OK则是用来判断该文件是否存在。由于access()只作权限的核查,并不理会文件形态或文件内容,因此,如果一目录表示为“可写入”,表示可以在该目录中建立新文件等操作,而非意味此目录可以被当做文件处理。例如,你会发现DOS的文件都具有“可执行”权限,但用execve()执行时则会失败。

返回值    若所有欲查核的权限都通过了检查则返回0值,表示成功,只要有一权限被禁止则返回-1。错误代码    EACCESS 参数pathname 所指定的文件不符合所要求测试的权限。

EROFS 欲测试写入权限的文件存在于只读文件系统内。

EFAULT 参数pathname指针超出可存取内存空间。

EINVAL 参数mode 不正确。

ENAMETOOLONG 参数pathname太长。

ENOTDIR 参数pathname为一目录。

ENOMEM 核心内存不足

ELOOP 参数pathname有过多符号连接问题。

EIO I/O 存取错误。

附加说明    使用access()作用户认证方面的判断要特别小心,例如在access()后再做open()的空文件可能会造成系统安全上的问题。

范例

#include

intmain()

{if (access(“/etc/passwd”,R_OK) = =0)

printf(“/etc/passwd can be read

”);

}

执行/etc/passwd can be read

(2)mkfifo

mkfifo(建立实名管道)

相关函数

pipe,popen,open,umask

表头文件

#include

#include

定义函数

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中。

错误代码

EACCESS 参数pathname所指定的目录路径无可执行的权限

EEXIST 参数pathname所指定的文件已存在。

ENAMETOOLONG 参数pathname的路径名称太长。

ENOENT 参数pathname包含的目录不存在

ENOSPC 文件系统的剩余空间不足

ENOTDIR 参数pathname路径中的目录存在但却非真正的目录。

EROFS 参数pathname指定的文件存在于只读文件系统内。

4. 命名管道实现服务器和客户端双向通信

4.1 封装命令管道类NamedPipe

enumOpenMode

{

ReadOnly= 1,

WriteOnly,

READWRITE

};classNamedPipe

{public://每次从管道最多读取的字节数

static const int PIPE_BUFF = 1024;

NamedPipe();

NamedPipe(const string&strPath, OpenMode mode);~NamedPipe();string read(intnSize);stringread();void write(const string&content);private:intm_fd;intm_mode;

};

NamedPipe实现

NamedPipe::NamedPipe()

{

}

NamedPipe::NamedPipe(const string&strPath, OpenMode mode)

:m_fd(-1), m_mode(mode)

{int nOpenMode = 0;if(mode ==ReadOnly)

{

nOpenMode=O_RDONLY;

}else if(mode ==WriteOnly)

{

nOpenMode=O_WRONLY;

}else if(mode ==READWRITE)

{

nOpenMode=O_RDWR;

}

cout<< "检查管道:" <

{

cout<< "管道不存在创建管道" <

{

cout<< "无法创建管道" <

}else{

cout<< "创建管道成功" <

}

}

cout<< "管道存在打开管道" <

m_fd=open(strPath.c_str(), nOpenMode);

}

NamedPipe::~NamedPipe()

{if(m_fd && m_fd != -1)

{

close(m_fd);

}

}string NamedPipe::read(intnSize)

{if(m_fd == -1)

{

cout<< "打开文件失败!" <

}char buff[PIPE_BUFF] = {0};int nReadSize = 0;string strContent = "";do{int nBytesToRead = 0;if(nReadSize + PIPE_BUFF

{

nBytesToRead=PIPE_BUFF;

}else{

nBytesToRead= nSize -nReadSize;

}

nBytesToRead=::read(m_fd, buff, nBytesToRead);if(nBytesToRead == -1)

{

cout<< "读取失败" <

}

nReadSize+=nBytesToRead;

strContent+= string(buff, nBytesToRead);

}while(nReadSize

}stringNamedPipe::read()

{if(m_fd == -1)

{

cout<< "打开文件失败!" <

}char buff[PIPE_BUFF] = {0};int nBytesToRead =::read(m_fd, buff, PIPE_BUFF);if(nBytesToRead == -1)

{

cout<< "PipeReadException" <

}return string(buff);

}void NamedPipe::write(const string&content)

{if(m_fd == -1)

{

cout<< "打开文件失败!" <

}int nWriteBytes =::write(m_fd, content.c_str(), content.length());if(nWriteBytes == -1)

{

cout<< "PipeWriteException" <

}

}

4.2 服务器和客户端实现

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#include "namepipe.h"

#define SERVER_W "serverWrite"

#define SERVER_R "serverRead"

#define RED_SIZE 1024

intmain()

{

NamedPipe ReadPipe(SERVER_R, READWRITE);

NamedPipe WritePipe(SERVER_W, READWRITE);int pid =fork();if(pid < 0)

{

cout<< "创建服务器子进程失败!" <

}else if(pid == 0)

{

cout<< "服务器子进程创建成功,用于读客户端信息" <

{

msg=ReadPipe.read();

cout<< msg.length() < 0)

{

cout<< "服务器接收到信息:" << msg <

{

cout<< "客户端请求断开连接" <

}

}

}

cout<< "服务器子进程没有资源可读,断开连接" <

exit(0);

}else{

cout<< "服务器父进程用于发送内容给客户端" <

{

WritePipe.write(msg);if(msg == "EOF")

{

cout<< "服务器请求断开连接"<

}

}

wait(NULL);

}return 0;

}

pipeserver.cpp

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#include "namepipe.h"

#define SERVER_W "serverWrite"

#define SERVER_R "serverRead"

#define RED_SIZE 64

intmain()

{

NamedPipe ReadPipe(SERVER_W, READWRITE);

NamedPipe WritePipe(SERVER_R, READWRITE);int pid =fork();if(pid < 0)

{

cout<< "创建客户端子进程失败!" <

}else if(pid == 0)

{

cout<< "客户端子进程创建成功,用于写客户端信息" <

{

WritePipe.write(msg);if(msg == "EOF")

{

cout<< "客户端子进程请求断开连接"<

}

}

cout<< "服客户端子进程断开连接" <

exit(0);

}else{

cout<< "客户端父进程用于读取服务器内容" <

{

msg=ReadPipe.read();if(msg.length() > 0)

{

cout<< "客户端父进程接收到信息:" << msg <

{

cout<< "服务器请求断开连接" <

}

}

}

wait(NULL);

}return 0;

}

pipeclient.cpp

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值