1. 进程间通信概述

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

1.1 进程间通信功能

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

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

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

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

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

2. 管道

2.1 管道特点

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

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

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

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

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

2.2 管道数据传输

2.3 函数

#include <unistd.h>
int pipe(int filedes[]); 功能:经由参数filedes返回两个文件描述符 参数: filedes为int型数组的首地址,其存放了管道的文件描述符fd[]、fd[]。 filedes[]为读而打开,filedes[]为写而打开 管道,filedes[]的输出是filedes[]的输入。 返回值:成功:返回 0 失败:返回-

2.4 例子

#include "intf.h"

#include <iostream>
#include <string.h>
using namespace std; #define BUFFSIZE 1024 int main(int argc, char *argv[])
{
int ParentFd[]; cout << "程序开始" << endl;
if(pipe(ParentFd) < )
{
perror("创建管道失败");
}
printf("创建管道成功\n"); int pid = fork();
if(pid < )
{
perror("创建进程失败");
}
else if(pid == )
{
printf("子进程:\n");
close(ParentFd[]);
cout << "请输入要写入的字符" << endl;
string s;
while(getline(cin, s))
{
write(ParentFd[], s.c_str(), s.length());
if(s == "quit")
{
exit();
}
} }
else
{
cout << "父进程:" << endl;
close(ParentFd[]);
while()
{
char msg[BUFFSIZE] = {};
read(ParentFd[], msg, BUFFSIZE);
cout << "父进程显示:" << msg << endl;
if(!strcmp(msg, "quit"))
{
exit();
}
}
} cout << "程序结束" << endl; return ;
}

3. 命名管道

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

3.1 函数介绍

(1)access

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

相关函数
    stat,open,chmod,chown,setuid,setgid
表头文件
    #include<unistd.h>
定义函数
    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<unistd.h>
int main()
{
if (access(“/etc/passwd”,R_OK) = =)
printf(“/etc/passwd can be read\n”);
}
执行
/etc/passwd can be read

(2)mkfifo

mkfifo(建立实名管道)
相关函数
    pipe,popen,open,umask
表头文件
    #include<sys/types.h>
    #include<sys/stat.h>
定义函数
    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

enum OpenMode
{
ReadOnly = ,
WriteOnly,
READWRITE
}; class NamedPipe
{
public:
// 每次从管道最多读取的字节数
static const int PIPE_BUFF = ; NamedPipe();
NamedPipe(const string& strPath, OpenMode mode);
~NamedPipe();
string read(int nSize);
string read();
void write(const string& content); private:
int m_fd;
int m_mode;
};

NamedPipe实现

NamedPipe::NamedPipe()
{ }
NamedPipe::NamedPipe(const string& strPath, OpenMode mode)
:m_fd(-), m_mode(mode)
{
int nOpenMode = ;
if(mode == ReadOnly)
{
nOpenMode = O_RDONLY;
}
else if(mode == WriteOnly)
{
nOpenMode = O_WRONLY;
}
else if(mode == READWRITE)
{
nOpenMode = O_RDWR;
}
cout << "检查管道:" << endl;
if(access(strPath.c_str(), F_OK) < )
{
cout << "管道不存在创建管道" << endl;
int ret = mkfifo(strPath.c_str(), );
if(ret < )
{
cout << "无法创建管道" << endl;
}
else{
cout << "创建管道成功" << endl;
}
}
cout << "管道存在打开管道" << endl;
m_fd = open(strPath.c_str(), nOpenMode);
} NamedPipe::~NamedPipe()
{
if(m_fd && m_fd != -)
{
close(m_fd);
}
}
string NamedPipe::read(int nSize)
{
if(m_fd == -)
{
cout << "打开文件失败!" << endl;
} char buff[PIPE_BUFF] = {};
int nReadSize = ;
string strContent = "";
do{
int nBytesToRead = ;
if(nReadSize + PIPE_BUFF < nSize)
{
nBytesToRead = PIPE_BUFF;
}
else
{
nBytesToRead = nSize - nReadSize;
} nBytesToRead = ::read(m_fd, buff, nBytesToRead);
if(nBytesToRead == -)
{
cout << "读取失败" << endl;
} nReadSize += nBytesToRead;
strContent += string(buff, nBytesToRead); }while(nReadSize < nSize); return strContent;
}
string NamedPipe::read()
{
if(m_fd == -)
{
cout << "打开文件失败!" << endl;
} char buff[PIPE_BUFF] = {}; int nBytesToRead = ::read(m_fd, buff, PIPE_BUFF);
if(nBytesToRead == -)
{
cout << "PipeReadException" << endl;
} return string(buff);
}
void NamedPipe::write(const string& content)
{
if(m_fd == -)
{
cout << "打开文件失败!" << endl;
}
int nWriteBytes = ::write(m_fd, content.c_str(), content.length()); if(nWriteBytes == -)
{
cout << "PipeWriteException" << endl;
}
}

4.2 服务器和客户端实现

#include "namepipe.h"

#define SERVER_W "serverWrite"
#define SERVER_R "serverRead"
#define RED_SIZE 1024
int main()
{
NamedPipe ReadPipe(SERVER_R, READWRITE);
NamedPipe WritePipe(SERVER_W, READWRITE); int pid = fork(); if(pid < )
{
cout << "创建服务器子进程失败!" << endl;
}
else if(pid == )
{
cout << "服务器子进程创建成功,用于读客户端信息" << endl;
string msg = "";
while()
{
msg = ReadPipe.read();
cout << msg.length() << endl;
if(msg.length() > )
{
cout << "服务器接收到信息:" << msg << endl; if(msg == "EOF")
{
cout << "客户端请求断开连接" << endl;
break;
}
}
}
cout << "服务器子进程没有资源可读,断开连接" << endl;
exit();
}
else{
cout << "服务器父进程用于发送内容给客户端" << endl;
string msg = "";
while(getline(cin, msg))
{
WritePipe.write(msg); if(msg == "EOF")
{
cout << "服务器请求断开连接"<< endl;
break;
} } wait(NULL);
} return ;
}

pipeserver.cpp

#include "namepipe.h"

#define SERVER_W "serverWrite"
#define SERVER_R "serverRead"
#define RED_SIZE 64
int main()
{
NamedPipe ReadPipe(SERVER_W, READWRITE);
NamedPipe WritePipe(SERVER_R, READWRITE); int pid = fork(); if(pid < )
{
cout << "创建客户端子进程失败!" << endl;
}
else if(pid == )
{
cout << "客户端子进程创建成功,用于写客户端信息" << endl;
string msg = "";
while(getline(cin, msg))
{
WritePipe.write(msg); if(msg == "EOF")
{
cout << "客户端子进程请求断开连接"<< endl;
break;
} } cout << "服客户端子进程断开连接" << endl;
exit();
}
else{
cout << "客户端父进程用于读取服务器内容" << endl;
string msg = "";
while()
{
msg = ReadPipe.read();
if(msg.length() > )
{
cout << "客户端父进程接收到信息:" << msg << endl; if(msg == "EOF")
{
cout << "服务器请求断开连接" << endl;
break;
}
}
} wait(NULL);
} return ;
}

pipeclient.cpp

linux之管道的更多相关文章

  1. linux 有名管道(FIFO)

    http://blog.csdn.net/firefoxbug/article/details/8137762 linux 有名管道(FIFO) 管道的缓冲区是有限的(管道制存在于内存中,在管道创建时 ...

  2. Linux的管道命令

    Linux的管道命令 管道命令(Pipe) 管道命令用"|"来表示,管道命令需要接收前一个命令的输出来进行操作,但不能处理前一个命令的错误. //选取界面:cut,grep cut ...

  3. Linux进程间通信—管道

    Linux下的进程通信手段基本上是从UNIX平台上的进程通信手段继承而来的.而对UNIX发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间 ...

  4. Linux有名管道的 阻塞VS非阻塞 读写

    参考文章: 关于有名管道open时阻塞的问题 Linux有名管道(FIFO)的阻塞和非阻塞读写 挖坑,日后填

  5. linux C 管道

    单一进程使用管道基本上毫无意义.管道一般用来子进程和父进程之间的通信,或者兄弟进程间的通信. 创建管道的主要函数是pipe #include<unistd.h> ]) pipe函数创建一个 ...

  6. linux保持管道中颜色显示

    在linux工作中,不同类型的文件以不同的颜色显示,如文件夹显示蓝色,压缩文件显示橘黄色,可执行文件显示为绿色,链接失效文件高亮显示等等: 有时候根据颜色可以快速鉴别,如我有时为了保持目录的完整性,会 ...

  7. linux有名管道fifo,进程间通信

    命名管道(FIFO)不同于无名管道之处在于它提供了一个路径名与之关联,以 FIFO 的文件形式存在于文件系统中,这样,即使与 FIFO 的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通 ...

  8. Linux用管道命令对文件的移动

    我的问题是这样的:我有一个文件夹,里面有大约有1000个文件,然后我想把这样的一部分文件给随机分成两部分,一部分含有100张,另外一部分含有剩下的所有的文件,这个时候如果是在Linux图形界面的话直接 ...

  9. Linux进程间通信 -- 管道(pipe)

    前言    进程是一个独立的资源管理单元,不同进程间的资源是独立的,不能在一个进程中访问另一个进程的用户空间和内存空间.但是,进程不是孤立的,不同进程之间需要信息的交互和状态的传递,因此需要进程间数据 ...

  10. Linux下管道重定向使用以及Shell编程(操作系统)

    实验名称:Linux的基本操作 实验目的: 1.了解管道和重定向 2.熟悉基本的Linux脚本的编写 实验环境:Ubuntu 12.4(32位,简体中文) 实验内容: 1.将当前用户目录下的文件清单输 ...

随机推荐

  1. 对Java 静态代码块的一些了解

    一 般情况下,如果有些代码必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的;需要在项目启动的时候就初始化,在不创建对象的情 况下,其他程序来调用的时候,需要使用静态方法,这种 ...

  2. redis 笔记04 服务器、复制

    服务器 1. 一个命令请求从发送到完成主要包括以下步骤: 1). 客户端将命令请求发送给服务器 2). 服务器读取命令请求,并分析出命令参数 3). 命令执行器根据参数查找命令的实现函数,然后执行实现 ...

  3. overflow应用场景

    overflow属性可以设置的值有5种: (1)visible  默认值,内容不会裁剪,呈现在元素框之外: (2)hidden 内容会被裁剪,并且子元素内容是不可见的: (3)scroll 内容会被裁 ...

  4. Please make sure the TESSDATA_PREFIX environment variable is set to your "tessdata" directory.

    tesseract的一个操作问题,简单记录 类似坑尽量少踩 运行 .\tesseract.exe .\1356445914_9857.jpg tstimg  报错如下:Please make sure ...

  5. Oracle sql plus中常用的几个命令

    1.set linesize 300(表示一行为300个字符) set linesize可以设置一行显示的字符数,默认情况下为80个字符 2.l(list) 可以显示缓冲区中的最后执行的内容 3.ru ...

  6. QT添加资源文件,并为工具栏添加图片

    1.右键工程,添加新文件,QT,QT Resource File. 2.选择res,添加前缀,添加文件,(把图片放在文件夹里,把文件夹放在工程目录下)选择图片 3.在ui中,下方有个Action Ed ...

  7. Linux下挂载windows的共享文件夹

    环境说明: 由于领导要求:现需要将某Linux服务器下的一个文件移动到某windows服务器下(服务器均在机房托管,要远程操作) 由于操作为一次性,则决定在windows下建立一个共享文件夹,linu ...

  8. LeetCode——Next Greater Element I

    LeetCode--Next Greater Element I Question You are given two arrays (without duplicates) nums1 and nu ...

  9. mac的一些配置

    1,基础知识 /etc/bashrc :是针对系统所有用户的全局变量,只有root用户才能修改这两个文件,对一般用户来说是他们是只读的.一般用户要想修改它们,可以在命令前加sudo,意思是以Root身 ...

  10. Delphi_时间间隔

    1. var dtOnlineDateTime, dt: TDateTime; begin dt := StrToDateTime('2017/6/28 16:41:30'); dtOnlineDat ...