linux 管道读写规则

关于socket阻塞与非阻塞情况下的recv、send、read、write返回值.zip 立即下载

一,管道读写规则

当没有数据可读时

  • O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。
  • O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。

当管道满的时候

  • O_NONBLOCK disable: write调用阻塞,直到有进程读走数据
  • O_NONBLOCK enable:调用返回-1,errno值为EAGAIN

如果所有管道写端对应的文件描述符被关闭,则read返回0

如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE

当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。

当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

Detail 参见:

http://man7.org/linux/man-pages/man7/pipe.7.html

二,验证示例

示例一:O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。

复制代码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> 

int main(void)
{
    int fds[2];
    if(pipe(fds) == -1){
        perror("pipe error");
        exit(EXIT_FAILURE);
    }
    pid_t pid;
    pid = fork();
    if(pid == -1){
        perror("fork error");
        exit(EXIT_FAILURE);
    }
    if(pid == 0){
        close(fds[0]);//子进程关闭读端
        sleep(10);
        write(fds[1],"hello",5);
        exit(EXIT_SUCCESS);
    }

    close(fds[1]);//父进程关闭写端
    char buf[10] = {0};
    read(fds[0],buf,10);
    printf("receive datas = %s\n",buf);
    return 0;
}
复制代码

结果:

QQ截图20130715221246

说明:管道创建时默认打开了文件描述符,且默认是阻塞(block)模式打开

所以这里,我们让子进程先睡眠10s,父进程因为没有数据从管道中读出,被阻塞了,直到子进程睡眠结束,向管道中写入数据后,父进程才读到数据

示例二:O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。

复制代码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> 

int main(void)
{
    int fds[2];
    if(pipe(fds) == -1){
        perror("pipe error");
        exit(EXIT_FAILURE);
    }
    pid_t pid;
    pid = fork();
    if(pid == -1){
        perror("fork error");
        exit(EXIT_FAILURE);
    }
    if(pid == 0){
        close(fds[0]);//子进程关闭读端
        sleep(10);
        write(fds[1],"hello",5);
        exit(EXIT_SUCCESS);
    }

    close(fds[1]);//父进程关闭写端
    char buf[10] = {0};
    int flags = fcntl(fds[0], F_GETFL);//先获取原先的flags
    fcntl(fds[0],F_SETFL,flags | O_NONBLOCK);//设置fd为阻塞模式
    int ret;
    ret = read(fds[0],buf,10);
    if(ret == -1){

        perror("read error");
        exit(EXIT_FAILURE);
    }

    printf("receive datas = %s\n",buf);
    return 0;
}
复制代码

结果:

QQ截图20130715222752

示例三:如果所有管道写端对应的文件描述符被关闭,则read返回0

复制代码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> 

int main(void)
{
    int fds[2];
    if(pipe(fds) == -1){
        perror("pipe error");
        exit(EXIT_FAILURE);
    }
    pid_t pid;
    pid = fork();
    if(pid == -1){
        perror("fork error");
        exit(EXIT_FAILURE);
    }
    if(pid == 0){
        close(fds[1]);//子进程关闭写端
        exit(EXIT_SUCCESS);
    }

    close(fds[1]);//父进程关闭写端
    char buf[10] = {0};

    int ret;
    ret = read(fds[0],buf,10);
    printf("ret = %d\n", ret);

    return 0;
}
复制代码

结果:

QQ截图20130715223735

可知确实返回0,表示读到了文件末尾,并不表示出错

示例四:如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE

复制代码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>

void sighandler(int signo);
int main(void)
{
    int fds[2];
    if(signal(SIGPIPE,sighandler) == SIG_ERR)
    {
        perror("signal error");
        exit(EXIT_FAILURE);
    }
    if(pipe(fds) == -1){
        perror("pipe error");
        exit(EXIT_FAILURE);
    }
    pid_t pid;
    pid = fork();
    if(pid == -1){
        perror("fork error");
        exit(EXIT_FAILURE);
    }
    if(pid == 0){
        close(fds[0]);//子进程关闭读端
        exit(EXIT_SUCCESS);
    }

    close(fds[0]);//父进程关闭读端
    sleep(1);//确保子进程也将读端关闭
    int ret;
    ret = write(fds[1],"hello",5);
    if(ret == -1){
        printf("write error\n");
    }
    return 0;
}

void sighandler(int signo)
{
    printf("catch a SIGPIPE signal and signum = %d\n",signo);
}
复制代码

结果:

QQ截图20130715225323

可知当所有读端都关闭时,write时确实产生SIGPIPE信号

示例五:O_NONBLOCK disable: write调用阻塞,直到有进程读走数据

复制代码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> 

int main(void)
{
    int fds[2];
    if(pipe(fds) == -1){
        perror("pipe error");
        exit(EXIT_FAILURE);
    }
    int ret;
    int count = 0;
    while(1){
        ret = write(fds[1],"A",1);//fds[1]默认是阻塞模式
        if(ret == -1){
            perror("write error");
            break;
        }
        count++;
    }

    return 0;
}
复制代码

结果:

QQ截图20130715231009

说明:fd打开时默认是阻塞模式,当pipe缓冲区满时,write操作确实阻塞了,等待其他进程将数据从管道中取走

示例六:O_NONBLOCK enable:调用返回-1,errno值为EAGAIN

复制代码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> 

int main(void)
{
    int fds[2];
    if(pipe(fds) == -1){
        perror("pipe error");
        exit(EXIT_FAILURE);
    }
    int ret;
    int count = 0;
    int flags = fcntl(fds[1],F_GETFL);
    fcntl(fds[1],F_SETFL,flags|O_NONBLOCK);
    while(1){
        ret = write(fds[1],"A",1);//fds[1]默认是阻塞模式
        if(ret == -1){
            perror("write error");
            break;
        }
        count++;
    }
    printf("the pipe capcity is = %d\n",count);

    return 0;
}
复制代码

结果:

QQ截图20130715231520

可知也出现EGIN错误,管道容量是65536字节

man 7 pipe说明:

Pipe capacity
       A pipe has a limited capacity.  If the pipe is full, then a write(2)
       will block or fail, depending on whether the O_NONBLOCK flag is set
       (see below).  Different implementations have different limits for the
       pipe capacity.  Applications should not rely on a particular
       capacity: an application should be designed so that a reading process
       consumes data as soon as it is available, so that a writing process
       does not remain blocked.

       In Linux versions before 2.6.11, the capacity of a pipe was the same
       as the system page size (e.g., 4096 bytes on i386).  Since Linux
       2.6.11, the pipe capacity is 65536 bytes.

三,管道写与PIPE_BUF关系

man帮助说明:
PIPE_BUF
       POSIX.1-2001 says that write(2)s of less than PIPE_BUF bytes must be
       atomic: the output data is written to the pipe as a contiguous
       sequence.  Writes of more than PIPE_BUF bytes may be nonatomic: the
       kernel may interleave the data with data written by other processes.
       POSIX.1-2001 requires PIPE_BUF to be at least 512 bytes.  (On Linux,
       PIPE_BUF is 4096 bytes.)  The precise semantics depend on whether the
       file descriptor is nonblocking (O_NONBLOCK), whether there are
       multiple writers to the pipe, and on n, the number of bytes to be
       written:

       O_NONBLOCK disabled, n <= PIPE_BUF
              All n bytes are written atomically; write(2) may block if
              there is not room for n bytes to be written immediately
       阻塞模式时且n<PIPE_BUF:写入具有原子性,如果没有足够的空间供n个字节全部写入,则阻塞直到有足够空间将n个字节全部写入管道       
       O_NONBLOCK enabled, n <= PIPE_BUF
              If there is room to write n bytes to the pipe, then write(2)
              succeeds immediately, writing all n bytes; otherwise write(2)
              fails, with errno set to EAGAIN.
      非阻塞模式时且n<PIPE_BUF:写入具有原子性,立即全部成功写入,否则一个都不写入,返回错误
       O_NONBLOCK disabled, n > PIPE_BUF
              The write is nonatomic: the data given to write(2) may be
              interleaved with write(2)s by other process; the write(2)
              blocks until n bytes have been written.
      阻塞模式时且n>PIPE_BUF:不具有原子性,可能中间有其他进程穿插写入,直到将n字节全部写入才返回,否则阻塞等待写入
       O_NONBLOCK enabled, n > PIPE_BUF
              If the pipe is full, then write(2) fails, with errno set to
              EAGAIN.  Otherwise, from 1 to n bytes may be written (i.e., a
              "partial write" may occur; the caller should check the return
              value from write(2) to see how many bytes were actually
              written), and these bytes may be interleaved with writes by
              other processes.
   非阻塞模式时且N>PIPE_BUF:如果管道满的,则立即失败,一个都不写入,返回错误,如果不满,则返回写入的字节数为1~n,即部分写入,写入时可能有其他进程穿插写入
  • 当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。
  • 当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

注:管道容量不一定等于PIPE_BUF

示例:当写入数据大于PIPE_BUF时

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>


#define ERR_EXIT(m) \
        do \
        { \
                perror(m); \
                exit(EXIT_FAILURE); \
        } while(0)

#define TEST_SIZE 68*1024

int main(void)
{
    char a[TEST_SIZE];
    char b[TEST_SIZE];
    char c[TEST_SIZE];

    memset(a, 'A', sizeof(a));
    memset(b, 'B', sizeof(b));
    memset(c, 'C', sizeof(c));

    int pipefd[2];

    int ret = pipe(pipefd);
    if (ret == -1)
        ERR_EXIT("pipe error");

    pid_t pid;
    pid = fork();
    if (pid == 0)//第一个子进程
    {
        close(pipefd[0]);
        ret = write(pipefd[1], a, sizeof(a));
        printf("apid=%d write %d bytes to pipe\n", getpid(), ret);
        exit(0);
    }

    pid = fork();

    
    if (pid == 0)//第二个子进程
    {
        close(pipefd[0]);
        ret = write(pipefd[1], b, sizeof(b));
        printf("bpid=%d write %d bytes to pipe\n", getpid(), ret);
        exit(0);
    }

    pid = fork();

    
    if (pid == 0)//第三个子进程
    {
        close(pipefd[0]);
        ret = write(pipefd[1], c, sizeof(c));
        printf("bpid=%d write %d bytes to pipe\n", getpid(), ret);
        exit(0);
    }


    close(pipefd[1]);
    
    sleep(1);
    int fd = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
    char buf[1024*4] = {0};
    int n = 1;
    while (1)
    {
        ret = read(pipefd[0], buf, sizeof(buf));
        if (ret == 0)
            break;
        printf("n=%02d pid=%d read %d bytes from pipe buf[4095]=%c\n", n++, getpid(), ret, buf[4095]);
        write(fd, buf, ret);

    }
    return 0;    
}
复制代码

结果:

QQ截图20130715235256

QQ截图20130715235322

可见各子进程间出现穿插写入,并没保证原子性写入,且父进程在子进程编写时边读。

python sci sci-hub 爬论文 sci-hub 爬虫 后续加入对于时间的排序,下载最新文献 参考: https://www.guanjihuan.com/archives/6846 https://blog.youkuaiyun.com/czh2637750821/article/details/115508922 阅读详情

相关推荐

固定翼飞行器建模(二)——MATLAB/Simulink建模、配平及线性化

MATLAB/Simulink固定翼建模、配平及线性化。

2302_80148937的博客 1万+

linux系统编程之管道(二):管道读写规则

一,管道读写规则 当没有数据可读时 O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。 O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。 当管道满的时候 O_NONBLOCK disable: write调用阻塞,直到有进程读走数据 O_NONBLOCK...

weixin_34185512的博客 677

300个fpga练手项目推荐

• 按键设置BPM,LED和蜂鸣器同步打拍(支持4/4、3/4拍)• 例:先实现DDR3控制器(基础),再构建视频处理流水线(集成)◦ 驱动小型e-Paper显示日期/时间(SPI接口,静态刷新)◦ 音频输入经FFT后,用LED柱状显示频率能量(8频段简化)◦ 通过HC-05模块接收手机指令,控制电机方向(前进/后退)• 随机点亮LED,用按钮响应,数码管显示反应时间(毫秒级)• 8个LED旋转闪烁,按钮停止后显示中奖编号(带减速动画)• 用4方向按键输入手势(如→→←↑),正确后点亮绿色LED。

qq_62784677的博客 7637

[Linux]socket阻塞模式下recv()返回11(EAGAIN )的原因

linux socket 阻塞模式下recv()返回11(EAGAIN )的可能原因:   1,设置了接收超时为非0。 参考至:http://stackoverflow.com/questions/735249/blocking-socket-returns-eagain   2,网络质量差,例如:wifi环境下的网络信号强度太弱 ...

玄冬Wong 6399

浅谈车联网概述-1

车联网技术目前在车企中应用广泛,车联网通过车载传感器、无线通信等技术,能够将车辆上百的传感器数据上传至云端,当前智能网联车辆可以理解为一个“大号”手机。

Hello, World! 新能源汽车智能网联工程师,分享日常工作思考。 559

原形网络(Prototypical Networks)基于PyTorch的实现

我在Jay2coomzz的基础上修改了数据处理方式和evaluation_model()方法,作为初学者若有不当之处恳请大家批评指正,原文链接如下: https://blog.youkuaiyun.com/weixin_38471579/article/details/102631018 数据集和源码链接将放到评论区 文章目录1 数据集一个简单的数据集介绍数据集处理2 搭建网络CNNProtonets 1 数据集 一个简单的数据集介绍 Omniglot数据集一共包含1623 类手写体,每一类中包含20 个样本。其中.

weixin_43872532的博客 6636

linux socket recv 失败,socket中的socket recv,行为错误

问候!我使用开发为socket服务器的linux中的unpv13e库,并监听一个端口将接受3个套接字客户端(最多),每个客户端都有自己的线程....虽然这3个客户端发送的速度非常快,但套接字服务器的recv功能会接收到来自客户端1的一半字符串,另一半来自客户端2,这很奇怪,因为我认为这3个套接字客户端将运行在不同的线程中,也有不同的套接字ID,所以我很好奇它为什么发生?让我解释一下以下代码:lis...

weixin_34997593的博客 1324

CDD那些事 - DID and SecurityAccess

本文介绍了SecurityAccessSID27的安全访问配置流程:1.通过StateGroups添加Level2群组;2.在Classes定义L2子功能;3.配置4步解锁流程,选择对应解锁等级;4.在DiagnosticInstance设置请求响应。同时说明了DID配置的两种方式:在DIDs页面定义或通过Identification页面创建,前者定义更全面。文章还提到ServiceList支持view/edit模式,其中edit模式可配置DID的多服务支持(如同时支持SID22读取和SID2E写入),但该

ziteng21的博客 255

Linux下设置socket()中网络层的read()和write()状态为阻塞或非阻塞态

阻塞模式:指的是当某个函数执行成功的条件当前不满足时,该函数会阻塞当前执行线程,程序执行流在超时时间到达或执行成功的条件满足后恢复继续执行。设置为非阻塞后,send会返回EAGAIN或者EWOULDBLOCK错误,此时可以调用select函数来监视何时可以发送数据。非阻塞模式:即使某个函数执行成功的条件不满足,该函数也不会阻塞当前执行线程,而是立即返回,继续执行程序流。Linux上的socket函数也可以在创建时将socket设置为非阻塞模式。二、如何将socket设置为非阻塞模式。socket函数定义。

qq_57023986的博客 2437

使用Python的OpenCV库进行三维重建点云

通过这些步骤,我们可以使用Python的OpenCV库进行三维重建,并生成对应的点云。当然,这只是一个简单的示例,实际的三维重建可能涉及更多的图像处理和计算步骤。在计算机视觉领域,三维重建是一项重要的任务,它可以将多个二维图像或视频序列转换为三维场景模型。在本文中,我们将介绍如何使用Python的OpenCV库进行三维重建,并生成相应的点云。以上是使用Python的OpenCV库进行三维重建点云的简要介绍和示例代码。最后,我们可以将计算得到的三维点云可视化。安装完成后,我们可以开始编写代码。

AuSwift的博客 1646

OpenClaw 在 Docker 容器中的部署实战——零配置启动

本文介绍了OpenClaw在Docker容器中的快速部署方法,对比了本地部署与容器化部署的优势。通过官方镜像和Docker Compose两种方式,5分钟即可完成部署,并详细讲解了配置管理方案(挂载配置文件和环境变量)。文章还提供了飞书集成配置方法,以及生产环境下的日志管理、资源限制、健康检查等优化建议。最后包含常见问题排查指南,帮助开发者快速实现OpenClaw的容器化部署。

刘一说的IT专栏 902

socket 的阻塞模式和非阻塞模式

在应用程序 A 与 应用程序 B 建立了 TCP 连接之后,假设应用程序 A 不断调用 send 函数,这样数据会不断拷贝至对应的内核缓冲区中,如果 B 那一端一直不调用 recv 函数,那么 B 的内核缓冲区被填满以后,A 的内核缓冲区也会被填满,此时 A 继续调用 send 函数会是什么结果呢?上面的示例验证了如果一端一直发数据,而对端应用层一直不取数据(或收取数据的速度慢于发送速度),则很快两端的内核缓冲区很快就会被填满,导致发送端调用 send 函数被阻塞。

qq_41854911的博客 6045

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Linux命名管道FIFO的读写规则

Linux命名管道FIFO的读写规则       《Linux程序设计(第3版)》对于Linux命名管道的读写规则详解的不够详细和清楚,查了些资料,在此总结一下: 1.从FIFO中读取数据:约定:如果一个进程为了从FIFO中读取数据而阻塞打开了FIFO,那么称该进程内的读操作为设置了阻塞标志的读操作。(1)如果有进程写打开FIFO,且当前FIFO为空,则对于设置了阻塞标志的

愤怒的小狐狸----博客专栏 2万+

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

管道(二)——管道读写规则、管道容量Pipe Capacity、原子性PIPE_BUF——linux系统编程

文章目录4种情况下的管道读写规则当没有数据可读(若父进程不写而子进程读)当管道满(若父进程写而子进程不读)管道容量Pipe Capacity若(父进程)写端突然关闭若(子进程)读端突然关闭linux写入原子性问题 本人的《APUE》《UNPv12》到啦!希望博文质量能有所提高! 4种情况下的管道读写规则 我们用代码简单试验在一般情况下(O_NONBLOCK disable,默认阻塞)的4种情况: 1.当没有数据可读 2.当管道满的时候 3.所有管道读端对应的文件描述符被关闭 4.写端对应的文件描述符被关闭

学习中 2447

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

linux系统编程之管道(二):管道读写规则和Pipe Capacity、PIPE_BUF

一、当没有数据可读时 O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。 O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。 示例程序如下:  C++ Code  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1

Meditation 9998

linux 管道读写规则【转】

(转自:https://blog.youkuaiyun.com/nodeathphoenix/article/details/23284157) 一,管道读写规则 当没有数据可读时 O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。 O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。 当管道满的时候 O_NONBLOC...

Uaena的博客 826

linux 管道数据的写入hi_管道的一些读写规则

当没有数据可读时O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。当管道满的时候O_NONBLOCK disable: write调用阻塞,直到有进程读走数据O_NONBLOCK enable:调用返回-1,errno值为EAGAIN如果所有管道写端对应的文件描述符被...

weixin_39815879的博客 152
上一篇: unix网络编程卷2的头文件unpipc.h下载和编译(转)
下一篇: FIFO阻塞式的打开和读写,管道阻塞式的读写
nodeathphoenix
博客等级 码龄16年 97粉丝 99原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值