【问题标题】:Using named pipe better way使用命名管道更好的方法
【发布时间】:2021-04-21 06:36:43
【问题描述】:

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

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

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

  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. 使用每个写入器的 3 个命名管道 + 在读取器中使用像 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 的共享内存方法就足够了?
哪个更好,值得推荐?

谢谢。

【问题讨论】:

  • 您是否需要跟踪数据的来源(哪个传感器)?除非传感器程序输出的传感器数据在其输出中包含该数据,否则第一种选择将无法判断数据的来源。
  • 实际上每个传感器应用程序都将数据编码和屏蔽数据包,数据包协议有自己的传感器ID!谢谢关心。
  • /app/sensor1 &amp; &gt;&gt; /tmp/tls/pipe &amp; 通常放在末端,比如首选/app/sensor1 &gt;&gt; /tmp/tls/pipe &amp;,以免与/app/sensor1 &amp;&gt;&gt; /tmp/tls/pipe 混淆。

标签: c linux select pipe


【解决方案1】:

管道上的最大消息大小保证是原子的,因此不会交错消息:PIPE_BUF。如果您的消息更大,则第一种方法需要信号量或某种同步。 POSIX 保证这至少为 512 字节。在 Linux 上,它是 4096。请参阅 man (7) pipe

在性能方面,我认为差异可以忽略不计。如果您在很短的时间内有许多小写入,您可能会看到第一种方法的性能要好一些。这是因为您只需要一个用户空间/内核空间开关:read。而对于第二个,您将需要 selectread。但是,在大多数情况下,我认为大部分时间都花在等待数据或复制数据上。等待readselect 没关系。

使用共享内存,您需要处理同步问题。这可能更快,但复杂且容易出错。如果您遇到严重的性能问题,您可以重新考虑这一点。

简而言之,我会推荐第一种方法。它也更容易扩展或重用。

【讨论】:

  • 你的意思是,信号量最好使用第一种方法,因为它具有较少的预置操作和易于重用,但差异可以忽略不计吗?非常感谢您的详细解释。
  • 对。而且,如果您可以将所有单独的消息保持在小于 PIPE_BUF 的范围内,那么您甚至不需要信号量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-30
  • 2011-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-12
相关资源
最近更新 更多