linux之管道

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

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

1. 进程间通信概述

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

1.1 进程间通信功能

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

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

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

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

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

linux之管道

2. 管道

2.1 管道特点

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

linux之管道

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

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

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

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

2.2 管道数据传输

linux之管道

2.3 函数

#include <unistd.h>
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 <iostream>
#include <string.h>
using namespace std;

#define BUFFSIZE 1024

int main(int argc, char *argv[]) 
{ 
    int ParentFd[2];
    
    cout << "程序开始" << endl;
    if(pipe(ParentFd) < 0)
    {
        perror("创建管道失败");
    }
    printf("创建管道成功\n");

    int pid = fork();
    if(pid < 0)
    {
        perror("创建进程失败");
    }
    else if(pid == 0)
    {
        printf("子进程:\n");
        close(ParentFd[0]);
        cout << "请输入要写入的字符" << endl;
        string s;
        while(getline(cin, s))
        {
            write(ParentFd[1], s.c_str(), s.length());
            if(s == "quit")
            {
                exit(0);
            }
        }
        
    }
    else
    {
        cout << "父进程:" << endl;
        close(ParentFd[1]);
        while(1)
        {
            char msg[BUFFSIZE] = {0}; 
            read(ParentFd[0], msg, BUFFSIZE);
            cout << "父进程显示:" << msg << endl;
            if(!strcmp(msg, "quit"))
            {
                exit(0);
            }
        }
    }

    cout << "程序结束" << endl;

    return 0;
} 

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) = =0)
        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 = 1,
    WriteOnly,
    READWRITE
};

class NamedPipe
{
public:
    // 每次从管道最多读取的字节数
    static const int PIPE_BUFF = 1024;

    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(-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 << "检查管道:" << endl; 
   if(access(strPath.c_str(), F_OK) < 0)
   {
       cout << "管道不存在创建管道" << endl;
       int ret = mkfifo(strPath.c_str(), 0777 );
       if(ret < 0)
       {
           cout << "无法创建管道" << endl; 
       }
       else{
           cout << "创建管道成功" << endl;
       }
   }
    cout << "管道存在打开管道" << endl; 
    m_fd = open(strPath.c_str(), nOpenMode);
}

NamedPipe::~NamedPipe()
{
    if(m_fd && m_fd != -1)
    {
        close(m_fd);
    }
}
string NamedPipe::read(int nSize)
{
    if(m_fd == -1)
    {
        cout << "打开文件失败!" << endl;
    }
   
    char buff[PIPE_BUFF] = {0};
    int nReadSize = 0;
    string strContent = "";
    do{
        int nBytesToRead = 0;
        if(nReadSize + PIPE_BUFF < nSize)
        {
            nBytesToRead = PIPE_BUFF;
        }
        else 
        {   
            nBytesToRead = nSize - nReadSize;
        }
  
        nBytesToRead = ::read(m_fd, buff, nBytesToRead);
        if(nBytesToRead == -1)
        {
            cout << "读取失败" << endl; 
        }

        nReadSize += nBytesToRead;
        strContent += string(buff, nBytesToRead);

    }while(nReadSize < nSize);

    return strContent;
}
string NamedPipe::read()
{
    if(m_fd == -1)
    {
        cout << "打开文件失败!" << endl;
    }
   
    char buff[PIPE_BUFF] = {0};
    
    int nBytesToRead = ::read(m_fd, buff, PIPE_BUFF);
    if(nBytesToRead == -1)
    {
        cout << "PipeReadException" << endl; 
    }

    return string(buff);
}
void NamedPipe::write(const string& content)
{
    if(m_fd == -1)
    {
        cout << "打开文件失败!" << endl;
    }
    int nWriteBytes = ::write(m_fd, content.c_str(), content.length());
  
    if(nWriteBytes == -1)
    {
        cout << "PipeWriteException" << endl; 
    }
}

4.2 服务器和客户端实现

linux之管道
linux之管道

#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 < 0)
    {
        cout << "创建服务器子进程失败!" << endl;
    }
    else if(pid == 0)
    {
        cout << "服务器子进程创建成功,用于读客户端信息" << endl;
        string msg = "";
        while(1)
        {
            msg = ReadPipe.read();
            cout << msg.length() << endl;
            if(msg.length() > 0)
            {
                cout << "服务器接收到信息:" << msg << endl;

                if(msg == "EOF")
                {
                    cout << "客户端请求断开连接" << endl;
                    break;
                }
            }
        }
        cout << "服务器子进程没有资源可读,断开连接" << endl;
        exit(0);
    }
    else{
        cout << "服务器父进程用于发送内容给客户端" << endl;
        string msg = "";
        while(getline(cin, msg))
        {
             WritePipe.write(msg);

            if(msg == "EOF")
            {
                cout << "服务器请求断开连接"<< endl;
                break;
            }
           
        }

        wait(NULL);
    }

    return 0;
}

pipeserver.cpp

linux之管道
linux之管道

#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 < 0)
    {
        cout << "创建客户端子进程失败!" << endl;
    }
    else if(pid == 0)
    {
        cout << "客户端子进程创建成功,用于写客户端信息" << endl;
        string msg = "";
        while(getline(cin, msg))
        {
             WritePipe.write(msg);

            if(msg == "EOF")
            {
                cout << "客户端子进程请求断开连接"<< endl;
                break;
            }
           
        }
        
        cout << "服客户端子进程断开连接" << endl;
        exit(0);
    }
    else{
        cout << "客户端父进程用于读取服务器内容" << endl;
        string msg = "";
        while(1)
        {
            msg = ReadPipe.read();
            if(msg.length() > 0)
            {
                cout << "客户端父进程接收到信息:" << msg << endl;

                if(msg == "EOF")
                {
                    cout << "服务器请求断开连接" << endl;
                    break;
                }
            }
        }

        wait(NULL);
    }

    return 0;
}

pipeclient.cpp

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/120114.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • EXCEL出错 8000401a

    EXCEL出错 8000401a
    检索COM类工厂中CLSID为{00024500-0000-0000-C000-000000000046}的组件时失败,原因是出现以下错误:8000401a
     
     
     
     
    解决方法:
     

    1:在服务器上安装office的Excel软件.
    2:在”开始”->”运行”中输入dcomcnfg.exe启动”组件服务”
    3:依次双击”组件服务”->”计算机”->”我的电脑”->”DCOM配

    2022年7月25日
    11
  • 使用Java判断闰年

    使用Java判断闰年我们在做这一题之前 我们首先要弄清楚什么是闰年 简而言之闰年就是可以被 4 整除不能被 100 整除 或者可以被 400 整除 那么这一年就是闰年 leapyear 然后就按照以上条件一步一步写代码 public nbsp static nbsp void nbsp main String args nbsp nbsp nbsp nbsp nbsp nbsp Scannersc newScanner System in nbsp nbsp nbsp nbsp nbsp nbsp System out printl

    2025年8月22日
    4
  • ZAB协议简介

    ZAB协议简介Zookeeper 使用 ZookeeperAto ZAB 协议来保障分布式数据一致性 ZAB 是一种支持崩溃恢复的消息广播协议 采用类似 2PC 的广播模式保证正常运行时性能 并使用基于 Paxos 的策略保证崩溃恢复时的一致性 在阅读本文前建议先了解 2PC 和 PaxosZAB 协议中节点存在四种状态 Leading 当前节点为集群 Leader 负责协调事务

    2026年1月21日
    0
  • 组合数递推的计算方法 c语言,组合数公式的递推公式

    组合数递推的计算方法 c语言,组合数公式的递推公式组合数公式的递推公式:c(m,n)=c(m-1,n-1)+c(m-1,n)。等式左边表示从m个元素中选取n个元素,而等式右边表示这一个过程的另一种实现方法:任意选择m中的某个备选元素为特殊元素,从m中选n个元素可以由此特殊元素的被包含与否分成两类情况,即n个被选择元素包含了特殊元素和n个被选择元素不包含该特殊元素。前者相当于从m-1个元素中选出n-1个元素的组合,即c(m-1,n-1);后者相当于…

    2022年7月15日
    19
  • text-decoration

    text-decoration

    2021年7月29日
    270
  • phpstorm激活码2021.5.1[在线序列号]

    phpstorm激活码2021.5.1[在线序列号],https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月20日
    47

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号