Linux中的高级IO函数(一)pipe socketpair dup

Linux提供了很多高级的I/O函数。它们并不像Linux基础I/O函数(比如open和read)那么常用(编写内核模块时一般要实现这些I/O函数),但在特定的条件下却表现出优秀的性能。这些函数大致分为三类:

用于创建文件描述符的函数,包括pipe、socketpair、dup/dup2函数。
用于读写数据的函数,包括readv/writev、sendfile、mmap/munmap、splice和tee函数。
用于控制I/O行为和属性的函数,包括fcntl函数。

本节先介绍第一类

一、pipe函数

pipe 函数用于创建一个管道,以实现进程间通信。

#include <unistd.h>

int pipe(int fd[2]);

pipe函数创建的这两个文件描述符fd[0]和fd[1]分别构成管道的两端,往fd[1]写入的数据可以从fd[0]读出。并且,fd[0]只能用于从管道读出数据,fd[1]则只能用于往管道写入数据,而不能反过来使用。如果要实现双向的数据传输,就应该使用两个管道。

默认情况下,这一对文件描述符都是阻塞的,若用read来读取一个空的管道,则read将被阻塞,直到管道内有数据可读。如果应用程序将fd[0]和fd[1]都设置为非阻塞的,则read和write会有不同的行为。

  • 如果管道的写端文件描述符fd[1]的引用计数减少至0,即没有任何进程需要往管道中写入数据,则针对该管道的读端文件描述符fd[0]的read操作将返回0,即读取到了文件结束标记(End Of File,EOF);

  • 如果管道的读端文件描述符fd[0]的引用计数减少至0,即没有任何进程需要从管道读取数据,则针对该管道的写端文件描述符fd[1]的write操作将失败,并引发SIGPIPE信号。

管道容量的大小默认是65536字节。我们可以使用fcntl函数来修改管道容量。

下面举一个在多进程程序中管道通信的例子:

#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main()
{
    int pipefd[2];
    char buf[1024];

    // 创建管道
    if (pipe(pipefd) == -1)
    {
        perror("pipe error! \n");
        return 1;
    }

    for (int i = 0; i < 8; i++)
    {
        // 创建子进程
        pid_t pid = fork();

        if (pid == -1)
        {
            perror("fork error!\n");
            return 1;
        }
        else if (pid == 0)
        {
            // 子进程关闭写端
            close(pipefd[1]);
            // 从管道读取数据
            memset(buf, 0, 1024);
            read(pipefd[0], buf, sizeof(buf));
            // 打印数据
            printf("pid = %d :Child process received: %s\n", getpid(), buf);
            // 子进程关闭读取端
            close(pipefd[0]);
            // 子进程直接break,以免创建更多的子进程
            break;
        }
    }

    if (getpid() != 0)
    {
        // 父进程关闭读取端
        close(pipefd[0]);
        // 向管道写入数据
        const char *message = "Hello from parent process";
        for (int i = 0; i < 8; i++)
        {
            write(pipefd[1], message, strlen(message));
            sleep(1);
        }
        // 在所有数据都写入后再关闭写入端
        close(pipefd[1]);
    }

    return 0;
}

生成了八个子进程,八个子进程阻塞在read处,等待父进程的消息,父进程发了八次消息,每次间隔1秒。看一下仿真

image-20240421223438140

二、socketpair函数

socketpair可以用于创建一堆相互连接的套接字,通常用于在进程之间通信

int socketpair(int domain, int type, int protocol, int sv[2]);

参数说明:

  • domain:指定地址族,通常为 AF_UNIX 表示 UNIX 域套接字。
  • type:指定套接字类型,通常为 SOCK_STREAM 表示面向连接的套接字。
  • protocol:指定使用的协议,通常为 0 表示默认协议。
  • sv[2]:用于存放创建的两个套接字的文件描述符的数组。

下面举个多进程的例子

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main()
{
    int socketfd[2];
    char buf[1024];

    // 创建一对相互连接的套接字
    if (socketpair(AF_UNIX, SOCK_STREAM, 0, socketfd) == -1) {
        perror("socketpair");
        return -1;
    }


    for (int i = 0; i < 8; i++)
    {
        // 创建子进程
        pid_t pid = fork();

        if (pid == -1)
        {
            perror("fork error!\n");
            return 1;
        }
        else if (pid == 0)
        {
            // 子进程关闭写端
            close(socketfd[1]);
            // 从管道读取数据
            memset(buf, 0, 1024);
            read(socketfd[0], buf, sizeof(buf));
            // 打印数据
            printf("pid = %d :Child process received: %s\n", getpid(), buf);
            // 子进程关闭读取端
            close(socketfd[0]);
            // 子进程直接break,以免创建更多的子进程
            break;
        }
    }

    if (getpid() != 0)
    {
        // 父进程关闭读取端
        close(socketfd[0]);
        // 向管道写入数据
        const char *message = "Hello from parent process";
        for (int i = 0; i < 8; i++)
        {
            write(socketfd[1], message, strlen(message));
            sleep(1);
        }
        // 在所有数据都写入后再关闭写入端
        close(socketfd[1]);
    }

    return 0;
}

例子和上面的 pipe 是一样的,看仿真:

image-20240422101424911

三、dup函数和dup2函数

dup函数和dup2函数可以把标准输入重定向到一个文件,或者把标准输出重定向到一个网络连接

#include <unistd.h>

int dup(int file_descriptor);
int dup2(int oldfd, int newfd);

dup函数创建一个新的文件描述符,该新文件描述符和原有文件描述符file_descriptor指向相同的文件、管道或者网络连接。并且dup返回的文件描述符总是取系统当前可用的最小整数值。

dup2函数可以将 oldfd 重定向到 newfd。如果newfd已经被程序使用,则系统会先将newfd所指的文件关闭。

**注意:**通过dup和dup2创建的文件描述符并不继承原文件描述符的属性,比如close-on-execnon-blocking等。

3.1、使用 dup2 将标准输出重定向到一个文件

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

int main() {
    // 打开或创建文件,以便将标准输入内容写入到该文件中
    int file_fd = open("output.txt", O_RDWR | O_CREAT, 0666);
    if (file_fd == -1) {
        perror("open");
        return 1;
    }

    // 将标准输出重定向到文件描述符指向的文件
	dup2(file_fd, STDOUT_FILENO)
    printf("newfd: hello, world\n");

    const char* buf = "oldfd: hello, world\n";
    write(file_fd, buf, strlen(buf)); 
    close(file_fd);
    return 0;
}

将标准输出重定向到 output.txt 文件,所以printf打印函数打印的字符串直接输出到了文件中,而不是控制台上。

image-20240422104522033

3.2、使用 dup2 将标准输入重定向到一个文件

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

int main() {
    // 打开或创建文件,以便将标准输入内容写入到该文件中
    int file_fd = open("output.txt", O_RDWR | O_CREAT, 0666);
    if (file_fd == -1) {
        perror("open");
        return 1;
    }

	dup2(file_fd, STDIN_FILENO)
    char buff[1024] = {0};
    read(STDIN_FILENO,buff,1024);
    printf("%s",buff);

    close(file_fd);
    return 0;
}

相当于直接从文件中读取数据作为标准输入了

image-20240422104857848

3.2、使用 dup 将标准输出重定向到一个文件

int main() {
    // 打开或创建文件,以便将标准输入内容写入到该文件中
    int file_fd = open("output.txt", O_RDWR | O_CREAT, 0666);
    if (file_fd == -1) {
        perror("open");
        return 1;
    }

    close(STDOUT_FILENO);
    dup(file_fd);

    printf("123");

    close(file_fd);
    return 0;
}

image-20240422110314962

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/572936.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Mongodb语法使用说明(含详细示例)

点击下载《Mongodb语法使用说明&#xff08;含详细示例&#xff09;》 1. 前言 MongoDB是一款高性能、开源、面向文档的NoSQL数据库&#xff0c;它使用类似JSON的BSON格式存储数据&#xff0c;提供了灵活的数据模型和强大的查询功能。本文将详细介绍MongoDB数据库的基本增删改…

CSS常用属性之(列表、表格、鼠标)属性,(如果想知道CSS的列表、表格、鼠标相关的属性知识点,那么只看这一篇就足够了!)

前言&#xff1a;在学习CSS的时候&#xff0c;必不可少的就要学习选择器和常见的属性&#xff0c;而本篇文章讲解的是CSS中的列表、表格、背景、鼠标属性。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客 大致了解一下本篇文章…

new String和直接赋值的一些问题

分析1 我们先看以下代码&#xff1a; String str1 "abc"; // 在常量池中String str2 new String("abc"); // 在堆上System.out.println(str1 str2)以上结果的输出是什么&#xff1f; 输出&#xff1a;false 前置知识&#xff1a; 在JVM中&#xff0c…

VForm3的文件上传后的一种文件回显方式

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://122.227.135.243:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a…

(C++) 内类生成智能指针shared_from_this介绍

文章目录 &#x1f601;介绍&#x1f914;类外操作&#x1f605;错误操作&#x1f602;正确操作 &#x1f914;类内操作&#x1f62e;std::enable_shared_from_this<>&#x1f62e;奇异递归模板 CRTP&#xff08;Curiously Recurring Template Pattern&#xff09;&#…

新手如何搭建测试平台?一文1800字从0到1实现【建议收藏】

01、职责 一个健康的测试平台体系&#xff0c;对测试人员的职责分工、协作模式会有不同的要求。 测试平台核心的职责是完成高质量的交付已满足业务需求。测试活动包括单元测试、集成测试、接口测试、性能测试等&#xff0c;都是通过这些测试手段&#xff0c;协同整个测试平台…

JavaEE 初阶篇-深入了解 UDP 通信与 TCP 通信(综合案例:实现 TCP 通信群聊)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 UDP 通信 1.1 DatagramSocket 类 1.2 DatagramPacket 类 1.3 实现 UDP 通信&#xff08;一发一收&#xff09; 1.3.1 客户端的开发 1.3.2 服务端的开发 1.4 实现 …

将Python机器学习模型集成到C++ Qt客户端应用程序中|Qt调用python详解

0、前言 有几个不同的选项可以将你的Python机器学习模型集成到你的C Qt客户端应用程序中。以下是一些可能的解决方案&#xff1a; 创建API&#xff1a; 将你的机器学习模型部署为一个API服务。你可以使用像Flask这样的轻量级Web框架来创建一个简单的HTTP服务。这样&#xff0…

Linux---Socket

网络套接字(socket) 网络通信仅仅是为了让两台主机间传送数据吗&#xff1f;数据是被谁需要的呢&#xff1f;--- 进程&#xff0c;所以网络通信的本质是两个进程间的通信。那么如何找到两台主机上的两个进程呢&#xff1f; 1、通过IP地址确定网络中的唯一一台主机 2、通过po…

Linux关闭swap分区操作[适用于CDH报警等]

1.查看swap分区挂载路径(没卵用) swapon -s 2.设置配置文件的swap配置 echo “vm.swappiness 0” > /etc/sysctl.conf 3.设置内存中的swap状态。有时候配置文件为0&#xff0c;但集群或服务仍然使用了swap分区&#xff0c;可能原因就是内存没有同步配置 echo “0” > …

C++入门----内联函数auto范围fornullptr指针

1.内联函数 顾名思义&#xff0c;内联函数也是函数的一种&#xff0c;我们在C语言的学习过程里面知道了函数和宏之间的区别和各自的优缺点&#xff1b; 函数的使用需要建立栈帧&#xff0c;宏的使用需要考虑各种符号的优先级问题&#xff0c;很容易出错&#xff0c;因为宏在使…

jmeter之跨线程关联

1&#xff09;_setproperty函数&#xff1a;将值保存成jmeter属性 2&#xff09;_property函数&#xff1a;在其他线程组中使用property函数读取属性 一、跨线程接口引用变量 1. 法一&#xff1a;jmeter自带函数_setProperty和_property 1. 1线程组 01 创建登录的【HTTP请求】…

Java知识总结---并发篇

线程 线程的状态 Java中线程可以有如下6中状态&#xff1a; NEW 新创建 RUNNABLE 可运行 BLOCKED 阻塞 WAITING 等待 TIMED WAITING 计时等待 TERMINATED 终止 线程的创建 &#xff08;1&#xff09;继承Thread类 public class ExtendsThread extends Thread { O…

后端工程师——C++工程师招聘需求

相比 Java 语言方向&#xff0c;C 入门简单&#xff0c;精通难&#xff0c;找工作竞争压力更小&#xff0c;但 C 依然是近年来招聘的热门岗位之一。本文将从以下三个方面进行详细讲解&#xff0c;帮助你对 C 相关岗位的就业前景、岗位要求、学习路线等有更充分的了解。 C工程师…

48-70V降12V/33V 5A高效同步降压DC-DC——AH1007

AH1007是一款高效率、高压外置MOSFET管降压芯片TEL&#xff1a;186*4884*3702*&#xff0c;芯片典型输入是8V~100V,输出 电压可调&#xff0c;AH1007最大输出电流可支持6A以上&#xff0c;需要注意板子的散热和温升。 AH1007典型开关频率为150KHz。轻载时会自动降低开关频率以…

SSRF—服务器请求伪造 漏洞详解

漏洞简述 SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造&#xff0c;由服务端发起请求的一个网络攻击&#xff0c;一般用来在外网探测或攻击内网服务&#xff0c;其影响效果根据服务器用的函数不同&#xff0c;从而造成不同的影响。 SSRF 形成的原因…

H5点击复制功能 兼容安卓、IOS

效果图 HTML代码 <div>链接&#xff1a;<span style"color: #FF8A21" click"CopyUrl" id"copyId"> https://blog.csdn.net/qq_51463650?spm1000.2115.3001.5343</span> </div>复制方法 const CopyUrl () > {let …

水库大坝安全白蚁监测系统解决方案

一、系统背景 白蚁作为河岸生态系统中的重要病害&#xff0c;不仅会导致水库大坝外部环境发生改变&#xff0c;甚至会引发水库大坝破坏&#xff0c;进而导致自身结构失去稳定性&#xff0c;严重影响水库大坝的正常运行。因此&#xff0c;治理水库大坝白蚁是确保水库大坝工程顺利…

chrome 浏览器 f12 如何查看 websocket 消息?

1. 打开目标页面 2. f12--》网络--》WS&#xff0c;然后刷新页面( 如果不刷页面&#xff0c;就会看不到 websocket 请求&#xff0c;因为 websocket 是长连接&#xff0c;页面加载后只发出一次连接请求&#xff0c;不像 http 接口&#xff0c;不用刷新页面&#xff0c;待会儿也…

Linux Docker下载镜像更改默认存储位置/usr/lib/docker

用于解决docker默认存储位置磁盘空间不足&#xff0c;切换存储位置 1、执行下面命令查看 现在docker的存储位置 docker info | grep "Docker Root Dir" 1.2、如果之前已经下载过镜像可以用mv命令把原来的镜像复制到新的地址 mv /var/lib/docker /data/docker 2、…