Linux IPC之有名管道

简介

无名管道在这篇笔记中有详细的介绍,包括半双工的pipe和全双工的socketpair;两者的共同特点是只能用于有亲缘关系的进程,比如父子进程。如果想要在任意进程间使用管道进行通信,则需要借助有名管道,即mkfifo来实现:

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);

成功返回0,失败返回-1.

  • pathname:FIFO的名称
  • mode:权限,在stat.h头文件中指定的,默认是O_CREATE | O_EXCL参数;如果已经存在,则返回EEXIST错误。也就是说,存在的情况下,使用open函数进程打开。

在使用FIFO时,必须先写再读,如果先读,则进程阻塞,这可能会产生死锁,一定要注意这点。

还有一个重要的地方:管道和FIFO的write都是原子操作,不必加锁,直接进行write操作即可。

与文件的不同之处

FIFO文件在使用上和普通文件有相似之处,但是也有不有
不同之处:

  1. 读取fifo文件的进程只能以”RDONLY”方式打开fifo文件。
  2. 写fifo文件的进程只能以”WRONLY”方式打开fifo
  3. fifo文件里面的内容被读取后,就消失了。但是普通文件里面的内容读取后还存在。

作者:萌小宏
来源:CSDN
原文:https://blog.csdn.net/best_fiends_zxh/article/details/52923560

作为守护进程的实例

我们开启一个后台的守护进程,而且该守护进程拥有一个FIFO。客户端通过FIFO向守护进程发送数据。注意,客户可以很容易向服务器发送数据,但是服务器却很难通过原始的FIFO发送数据。更好的解决办法是,守护进程维护的FIFO仅仅作为一个消息通信装置,用户把自己的请求(比如新建的FIFO名称)发送给守护进程,然后守护进程通过该消息寻找指定的FIFO,然后进行通信,给出一个参考图。

代码实例

注意,这里为了方便,把数据改成了可读可写的类型。实际过程中,可以根据需要选择权限,但是注意,不要弄错了,否则会永远阻塞。。
Server

#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <strings.h>
#include <unistd.h>
#include <time.h>
#include <cstring>

const char *PATH = "/home/erick/Desktop/fifo.serv";

bool stop_server = false;


void sig_handler(int sig) {
    if (sig != SIGINT) {
        return;
    }
    stop_server = true;
    puts("stop server...");
}


int main() {
    if ((mkfifo(PATH, 0666) < 0) && (errno != EEXIST)) {
        perror("mkfifo() error\n");
        exit(EXIT_FAILURE);
    }

    if ((open(PATH, O_CREAT | O_EXCL | O_RDWR, 7777) < 0) && (errno != EEXIST)) {
        perror("pipe file does not exists\n");
        exit(EXIT_FAILURE);
    }

    int readfd = open(PATH, O_RDWR);
    int dummyfd = open(PATH, O_RDWR);  // 永远不使用

    struct sigaction sa;
    bzero(&sa, sizeof(sa));
    sa.sa_flags = SA_RESTART;
    sa.sa_handler = sig_handler;
    if (sigaction(SIGINT, &sa, nullptr) < 0) {
        perror("sigaction() error\n");
        exit(EXIT_FAILURE);
    }

    while (!stop_server) {
        char buf[1024];
        memset(buf, 0, sizeof(buf));
        read(readfd, buf, 1024);
        printf("get child req: %s\n", buf);
        int writefd = open(buf, O_RDWR);
        if (writefd < 0) {
            printf("open %s failed\n", buf);
            exit(EXIT_FAILURE);
        }

        // 获取当前系统时间
        time_t t = time(nullptr);
        struct tm tm = *localtime(&t);
        snprintf(buf, 1024, "now: %d-%d-%d %d:%d:%d\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
                 tm.tm_min, tm.tm_sec);

        write(writefd, buf, strlen(buf));

        sleep(1);
    }

    close(readfd);
    close(dummyfd);

    exit(EXIT_SUCCESS);
}

服务器发送给客户端当前的系统时间:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <cstring>
#include <signal.h>

const char *PATH = "/home/erick/Desktop/fifo.serv";

bool stop_server = false;


void sig_handler(int sig) {
    if (sig != SIGINT) {
        return;
    }
    stop_server = true;
    puts("stop server...");
}


int main() {
    // 有名管道设置为自己的进程号
    char path[100];
    snprintf(path, 100, "/home/erick/Desktop/fifo.%ld", (long) getpid());
    if (mkfifo(path, 0666) < 0) {
        perror("mkfifo() error\n");
        exit(EXIT_FAILURE);
    }

    if ((open(path, O_CREAT | O_EXCL | O_RDWR, 7777) < 0) && (errno != EEXIST)) {
        perror("pipe file does not exists\n");
        exit(EXIT_FAILURE);
    }
    puts("before");
    int readfd = open(path, O_RDWR);
    puts("readfd");
    int serverfd = open(PATH, O_RDWR);
    if (serverfd < 0) {
        perror("open() error\n");
        exit(EXIT_FAILURE);
    }
    puts("server");

    struct sigaction sa;
    bzero(&sa, sizeof(sa));
    sa.sa_flags = SA_RESTART;
    sa.sa_handler = sig_handler;
    if (sigaction(SIGINT, &sa, nullptr) < 0) {
        perror("sigaction() error\n");
        exit(EXIT_FAILURE);
    }

    if (write(serverfd, path, strlen(path)) < 0) {
        perror("write error\n");
        exit(EXIT_FAILURE);
    }

    char buf[1024];
    if (read(readfd, buf, 1024) < 0) {
        perror("read() error\n");
        exit(EXIT_FAILURE);
    }

    printf("system time: %s\n", buf);

    exit(EXIT_SUCCESS);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值