04.管道

DUP函数和DUP2函数的应用

#include <unistd.h>
int dup(int oldfd);
功能 :
复制 oldfd 文件描述符,并分配一个新的文件描述符,新的文件描述符是调用进程文件描述符表中最小可用的文件描述符。
参数:
要复制的文件描述符 oldfd。
返回值:
成功:新文件描述符。
失败:返回-1,错误代码存于 errno 中。

int dup2(int oldfd, int newfd);//dup2使用的比较多
功能:
复制一份打开的文件描述符 oldfd,并分配新的文件描述符 newfd, newfd 也标识 oldfd 所标识的文件。
注意:
newfd 是小于文件描述符最大允许值的非负整数, 如果 newfd 是一个已经打开的文件描述符,则首先关闭该文件,然后再复制。
参数:
要复制的文件描述符 oldfd分配的新的文件描述符 newfd
返回值:
成功:返回 newfd失败:
返回-1,错误代码存于 errno 中

DUP函数的作用

dup 和 dup2 是两个非常有用的系统调用,都是用来复制一个文件的描述符,使新的文件描述符也标识旧的文件描述符所标识的文件。

类似于fork函数,创建一个子进程,子进程是对父进程的复制,dup相当于对文件描述符的复制,复制出来的文件描述符,可以和原来的文件描述符一样操作同一个文件,dup也是一种进程间通信的方式。

dup的应用

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

int main(void)
{
    int newfd;
/*
#define STDIN_FILENO 0 //标准输入的文件描述符
#define STDOUT_FILENO 1 //标准输出的文件描述符
#define STDERR_FILENO 2 //标准错误的文件描述符
*/
// int dup(int oldfd);

newfd=dup(STDOUT_FILENO);
if(newfd==-1)
{
    printf("复制文件描述符出错\n");
    exit(-1);//return -1;
}
printf("newfd-->%d\n",newfd);

write(newfd,"hello world\n",13);

return 0;
}

dup2的应用

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>

int main(void)
{
    int newfd;
    int oldfd;
/*
#define STDIN_FILENO 0 //标准输入的文件描述符
#define STDOUT_FILENO 1 //标准输出的文件描述符
#define STDERR_FILENO 2 //标准错误的文件描述符
*/
// int dup(int oldfd);
oldfd=open("file1.txt",O_CREAT | O_WRONLY | O_TRUNC,0644);
printf("oldfd-->%d\n",oldfd);

newfd=dup2(oldfd,5);
// newfd=dup(oldfd);
printf("newfd-->%d\n",newfd);
pid_t pid=fork();
if(pid==0)
{
    printf("son.....\n");
    //子进程
    write(newfd,"this is son\n",12);
}

else 
{
     //子进程
    printf("father.....\n");
    write(newfd,"this is father\n",15);
    close(oldfd);
    wait(NULL);//回收任意一个子进程资源
}

close(newfd);


return 0;
}

管道:

fd[0]:用于读操作

fd[1]:用于写操作

也可以理解为,fd[0]和fd[1]就是管道的两个端

管道的特性:

1、半双工,数据在同一时刻只能在一个方向上流动。
2、数据只能从管道的一端写入,从另一端读出。
3、写入管道中的数据遵循先入先出的规则(FIFO)。
4、管道所传送的数据是无格式的,这要求管道的读出方与写入方必须事先约定好数据
的格式,如多少字节算一个消息等。
5、管道不是普通的文件,不属于某个文件系统,其只存在于内存中。
    管道就是一个文件,存在于系统内部,不需要我们工程师创建
6、管道在内存中对应一个缓冲区。不同的系统其大小不一定相同。
7、从管道读数据是一次性操作,数据一旦被读走,它就从管道中被抛弃,释放空间以
便写更多的数据。
8、管道没有名字,只能在具有公共祖先的进程之间使用--无名管道。

进程之间都是独立的,但是他们在内核态都是相同的,用户态(也就是下图中用户空间--进程控制块)

无名管道 pipe函数

#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

例程1:无名管道读写

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>

int fd[2];
int main(void)
{
    int ret;
    //创建管道

    ret=pipe(fd);
    if(ret==-1)
    {
        perror("pipe:");
        exit(-1);
    }
    printf("fd[0]:%d  fd[1]:%d \n",fd[0],fd[1]);

    pid_t pid=fork();
    if(pid==0)
    {
        //子进程中对管道进行读操作
        char buf[128]={0};
        read(fd[0],buf,sizeof(buf));//阻塞性
        printf("buf-->%s\n",buf);
        close(fd[0]);
    }
    else
    {
        //父进程中对管道进行写操作

        write(fd[1],"zhengzhou 2302\n",15);
        close(fd[1]);
        wait(NULL);
    }
    return 0;
}

例程2:写满管道 写端被阻塞

管道是一个内核中文件,大小是多少????

管道中一直写数据,不去读,在溢出的时候,将会阻塞

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>

int fd[2];
int main(void)
{
    int ret;
    //创建管道

    ret=pipe(fd);
    if(ret==-1)
    {
        perror("pipe:");
        exit(-1);
    }
    printf("fd[0]:%d  fd[1]:%d \n",fd[0],fd[1]);

    pid_t pid=fork();
    if(pid==0)
    {
        //子进程中对管道进行读操作
        // char buf[128]={0};
        // read(fd[0],buf,sizeof(buf));//阻塞性
        // printf("buf-->%s\n",buf);
        getchar();//

        close(fd[0]);
    }
    else
    {
        char str='A';
        //父进程中对管道进行写操作
        for(int i=0;i<70000;i++)
        {
            write(fd[1],&str,1);
            printf("count-->%d\n",i);
        }
       
        close(fd[1]);
        wait(NULL);
    }
    return 0;
}

不同的Ubuntu系统,管道的大小可能是不一样

1804版本--管道64KB

有名管道

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
有名管道特性:

命名管道(FIFO)和管道(pipe)基本相同,但也有一些显著的不同, 其特点是:

1、半双工,数据在同一时刻只能在一个方向上流动。
2、写入 FIFO 中的数据遵循先入先出的规则。
3、 FIFO 所传送的数据是无格式的,这要求 FIFO 的读出方与写入方必须事先约定好数
据的格式,如多少字节算一个消息等。
4、 FIFO 在文件系统中作为一个特殊的文件而存在,但 FIFO 中的内容却存放在内存(磁盘)中--可见的。
5、管道在内存中对应一个缓冲区。不同的系统其大小不一定相同。
6、从 FIFO 读数据是一次性操作,数据一旦被读,它就从 FIFO 中被抛弃,释放空间以
便写更多的数据。
7、当使用 FIFO 的进程退出后, FIFO 文件将继续保存在文件系统中以便以后使用。
8、 FIFO 有名字,不相关的进程可以通过打开命名管道进行通信。

操作 FIFO 文件时的特点

系统调用的 I/O 函数都可以作用于 FIFO,如 open、 close、 read、 write 等。

特点一:

不指定 O_NONBLOCK(即 open 没有位或 O_NONBLOCK)

1、 open 以只读方式打开 FIFO 时,要阻塞到某个进程为写而打开此 FIFO

2、 open 以只写方式打开 FIFO 时,要阻塞到某个进程为读而打开此 FIFO。

mkfifo函数:
表头文件
    #include<sys/types.h>
    #include<sys/stat.h>
定义函数
    int mkfifo(const char * pathname,mode_t mode);
    参数:pathname--有名管道(文件)名字
    mode--文件权限
    1、当使用O_NONBLOCK 旗标时,打开FIFO 文件来读取的操作会立刻返回,但是若还没有其他进程打开FIFO 文件来读取,则写入的操作会返回ENXIO 错误代码。
    2、没有使用O_NONBLOCK 旗标时,打开FIFO 来读取的操作会等到其他进程打开FIFO文件来写入才正常返回。同样地,打开FIFO文件来写入的操作会等到其他进程打开FIFO 文件来读取后才正常返回。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>

int fd[2];
int main(void)
{
    int ret;
   char buf[128]={0};
    ret=mkfifo("fifo_test",0666);
    // if(ret!=0)
    // {
    //     perror("mkfifo:");
    //     exit(-1);
    // }
     int fd=open("fifo_test",O_RDONLY);

    //  write(fd,"zhengzhou_gaoxinqu\n",19);
    read(fd,buf,128);
    printf("buf:%s\n",buf);
    close(fd);

    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>

int fd[2];
int main(void)
{
    int ret;
    //创建管道
    ret=mkfifo("fifo_test",0666);
    // if(ret!=0)
    // {
    //     perror("mkfifo:");
    //     exit(-1);
    // }
     int fd=open("fifo_test",O_WRONLY);

     write(fd,"zhengzhou_gaoxinqu\n",19);

    close(fd);

    return 0;
}

单机版本的聊天室功能

1.不同的进程之间可以互相传输数据

不同的进程--不同用户---给每一个用户起一个唯一的名字

名字---通过键盘输入

建议:发送数据和接受数据使用不同的进程实现

比如:父进程发送数据

子进程接收数据

相关推荐

  1. <span style='color:red;'>04</span>.<span style='color:red;'>管道</span>

    04.管道

    2024-03-16 01:58:01      47 阅读
  2. 医疗实施-项目管理04-需求调研

    2024-03-16 01:58:01       31 阅读
  3. Go语言学习06~07 错误处理和包管理

    2024-03-16 01:58:01       42 阅读
  4. web server apache tomcat11-04-manager 如何管理

    2024-03-16 01:58:01       37 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-16 01:58:01       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-16 01:58:01       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-16 01:58:01       87 阅读
  4. Python语言-面向对象

    2024-03-16 01:58:01       96 阅读

热门阅读

  1. 华为认证大数据工程师(HCIA-Big Data)--填空题

    2024-03-16 01:58:01       38 阅读
  2. 串口1234

    2024-03-16 01:58:01       37 阅读
  3. Linux socket服务器

    2024-03-16 01:58:01       42 阅读
  4. HDOJ 2050

    2024-03-16 01:58:01       40 阅读
  5. 前端面试练习24.3.15

    2024-03-16 01:58:01       36 阅读
  6. C++/CLI学习笔记1(快速打通c++与c#相互调用的桥梁)

    2024-03-16 01:58:01       42 阅读
  7. Android13 客制化U盘挂载路径

    2024-03-16 01:58:01       39 阅读
  8. ArrayList 是线程安全的么?

    2024-03-16 01:58:01       42 阅读
  9. R在直方图上添加一个更平滑的密度曲线

    2024-03-16 01:58:01       39 阅读
  10. JVM配置调优

    2024-03-16 01:58:01       45 阅读
  11. C语言程序设计(第四版)—习题11程序设计题

    2024-03-16 01:58:01       38 阅读