进程通信(一) 无名管道和有名管道

一、无名管道

1.1、特点:

1、没有名字,获取文件描述符的方法只有在创建时获得。

          即无法通过open fopen 等函数获取文件描述符

2、第一个特点决定了无名管道通信只能存在于亲缘进程之间的通信。

         即使用 fork 函数创建的进程之间

3、无名管道通信可被中断,即不能保证原子性(查百度吧,恶心的东西)

相关函数
函数原型       :int pipe(int pipefd[2])
return        :0---->成功
               -1--->失败
int pipefd[2] :pipefd[0]---->该文件描述符只有读取权限
                pipefd[1]---->该文件描述符只有写入权限

 

 

1.2、相关事例代码

/******头文件自己写吧********/



#define BUFLEN 100
int main(void)
{
    //信息存放
    char buf[BUFLEN];
    bzero(&buf, sizeof(buf));

    //准备数组存放无名管道文件描述符
    int fd[2];
    int ret = pipe(fd);
    if (ret == -1)
    {
        perror("pipe() filed");
        exit(0);
    }

    pid_t pid = fork();
    
    if (pid == -1)
    {
        perror("fork() filed");
        exit(0);
    }
    //子进程发送信息
    if (pid == 0)
    {
        printf("请输入给父进程的消息\n");
        fgets(buf, 100, stdin);
        write(fd[1], buf, strlen(buf));
        exit(0);
    }

    //父进程接收信息
    if (pid > 0)
    {
        read(fd[0], buf, strlen(buf));
        printf("收到子进程消息: %s\n", buf);
        wait(NULL);
        exit(0);
    }
    
}

程序最后没有关闭文件操作:因为完全没有必要

二、有名管道

2.1、特点

1、有名字,即可以通过 open 打开有名管道,即可以获得文件描述符。

2、有名字决定了有名管道可以在任意进程之间进行通信,因为可以在任意

进程获得有名管道的文件描述符。

相关函数
函数原型: int mkfifo(const char *pathname, mode_t mode)
return     : 0---->成功
             -1--->失败
pathname   : 创建有名管道的名字(包括路径名)
mode       : 参考 open 函数的参数 mode  

注意:pathname 不能在共享文件下,因为管道是在 Linux 系统中特有的,
        无法在 windows 系统下创建
常用相关错误码 :errno
    EACCESS 参数pathname所指定的目录路径无可执行的权限
    EEXIST 参数pathname所指定的文件已存在。
    ENAMETOOLONG 参数pathname的路径名称太长。
    ENOENT 参数pathname包含的目录不存在
    ENOSPC 文件系统的剩余空间不足
    ENOTDIR 参数pathname路径中的目录存在但却非真正的目录。
    EROFS 参数pathname指定的文件存在于只读文件系统内。

             

2.2、相关事例代码

2.2.1、发送端

/********自己写头文件********/
#define BUFLEN 100
#define FIFO "/home/gec/fifo"
int main(void)
{
    char buf[BUFLNE];
    bzero(&buf, sizeof (buf));
    //创建无名管道
    int ret = mkfifo(FIFO, 0644);

    //判断出错原因
    if(ret == -1)
    {
        if (error != EEXIST)
        {
            perror("mkfifo() filed");
            exit(0);            
        }
    }

    //数据写入有名管道
    int fd = open(FIFO, O_RDWR);
    fgets(buf, 100, stdin);
    write(fd, buf, strlen(buf));
    return 0;
}

 

2.2.2、接收端

/********就是不写头文件********/
#define BUFLEN 100
#define FIFO "/home/gec/fifo"

int main(void)
{
    char buf[BUFLNE];
    bzero(&buf, sizeof (buf));
    //创建无名管道
    int ret = mkfifo(FIFO, 0644);

    //判断出错原因
    if(ret == -1)
    {
        if (error != EEXIST)
        {
            perror("mkfifo() filed");
            exit(0);            
        }
    }

    //将数据读出有名管道
    int fd = open(FIFO, O_RDWR);
    read(fd, buf, strlen(buf));
    printf("收到发送端消息:%s\n", buf);
    return 0;
}

三、检测管道缓冲区大小

3.1、直接上代码吧

//程序功能:检测有名管道缓冲区大小。(无名管道类推即可)
/************头文件***************/
int main(void)
{
    //打开管道,不做判断了,如果出错请使用管道创建函数
    int fd = open("/home/etc/fifo", O_RDWR);

    //设置管道为非阻塞,这样写入失败会返回 -1
    long state = fcntl(fd, F_GETFL);
    state |= NONBLOCK;
    fcntl(fd, F_GETFL, state);

    char buf = 'a';
    int i = 0;
    while(-1 != (write(fd, &buf, sizeof (buf) ) ) )
        i++;
    printf("有名管道缓冲区大小:%d字节\n", i);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41985711/article/details/82379816