使用命名管道更好的方式

问题描述 投票:0回答:1

我已经有3个程序了,
分别通过 TLS 获取传感器数据将其发送到我的远程服务器

我想精简 TLS 标头,
所以我决定将以上程序分开
3 *(传感器数据获取程序)+ 1 *(tls 仅发送程序),
使用命名的 PIPE 作为进程间通信(不是套接字)。

但是现在我想知道哪个更好

  1. 使用 1 个命名管道和 3 个写入器 + 1 个读取器

    #!/bin/sh
    mkfifo /tmp/tls/pipe
    /app/sensor1 & >> /tmp/tls/pipe
    /app/sensor2 & >> /tmp/tls/pipe
    /app/sensor3 & >> /tmp/tls/pipe
    /app/tls_sender /tmp/tls/pipe
    
  2. 每个writer使用3个命名管道+在reader中像

    select()
    一样使用IO复用?

    #!/bin/sh
    mkfifo /tmp/tls/pipe1
    mkfifo /tmp/tls/pipe2
    mkfifo /tmp/tls/pipe3
    /app/sensor1 & >> /tmp/tls/pipe1
    /app/sensor2 & >> /tmp/tls/pipe2
    /app/sensor3 & >> /tmp/tls/pipe3
    /app/tls_sender /tmp/tls/pipe1 /tmp/tls/pipe2 /tmp/tls/pipe3
    

与 tls 发件人类似

#define SENSOR_NUM 3

int tls_flags[SENSOR_NUM];
char huge_buffer[HUGE_NUM];
int tls_send(int idx, char* buf) {
    // set flags for each readfds index
    // if all index counts to some threshold, send huge_buffer at once
}

int main(int argc, char *argv[]) {
    ...
    int fd[SENSOR_NUM];
    int state;
    char buf[255];
    fd_set readfds;

    FD_ZERO(&readfds);
    for(int i=0; i<SENSOR_NUM; i++)
    {
        fd[i] = open(argv[i+1], O_RDONLY);
        FD_SET(fd[i], &readfds);
    }
    while(1) {
        state = select(fd[2]+1, &readfs, NULL, NULL, NULL);
        switch(state)
        {
            // case -1: error exception
            // case 0 : no send
            default:
                for (int i=0; i<SENSOR_NUM; i++){
                    if (FD_ISSET(fd[i], &readfds))
                        read(fd[i], buf, 255);
                        tls_send(i, buf);
                }
                break;
        }
    }
    ...
}

我想前者会更容易实现并且更快,但后者会更稳定,但我不确定。

前者不使用信号量什么的够稳定吗?
或者后者更快或更脆弱?
或者甚至没有 PIPE 的共享内存方法就足够了?
哪一款比较好,值得推荐?

谢谢。

c linux pipe posix-select
1个回答
1
投票

管道上有最大消息大小,保证是原子的,因此不会交错消息:

PIPE_BUF
。如果您的消息较大,则第一种方法将需要信号量或某种同步。 POSIX 保证该值至少为 512 字节。在 Linux 上,它是 4096。请参阅 man (7) pipeline

就性能而言,我认为差异可以忽略不计。如果您在很短的时间内有许多小写入,则第一种方法可能会获得更好的性能。这是因为您只需要一个用户空间/内核空间开关:打开

read
。而对于第二个,您需要
select
read
。然而,在大多数情况下,我认为大部分时间都花在等待数据或复制数据上。等待
read
select
并不重要。

使用共享内存,您需要处理同步问题。这“可能”会更快,但很复杂并且容易出错。如果您遇到严重的性能问题,您可以重新考虑这一点。 总之,我推荐第一种方法。扩展或重用也更容易。

© www.soinside.com 2019 - 2024. All rights reserved.