我已经有3个程序了,
分别通过 TLS 获取传感器数据并将其发送到我的远程服务器。
我想精简 TLS 标头,
所以我决定将以上程序分开
3 *(传感器数据获取程序)+ 1 *(tls 仅发送程序),
使用命名的 PIPE 作为进程间通信(不是套接字)。
但是现在我想知道哪个更好
使用 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
每个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 的共享内存方法就足够了?
哪一款比较好,值得推荐?
谢谢。
管道上有最大消息大小,保证是原子的,因此不会交错消息:
PIPE_BUF
。如果您的消息较大,则第一种方法将需要信号量或某种同步。 POSIX 保证该值至少为 512 字节。在 Linux 上,它是 4096。请参阅 man (7) pipeline
就性能而言,我认为差异可以忽略不计。如果您在很短的时间内有许多小写入,则第一种方法可能会获得更好的性能。这是因为您只需要一个用户空间/内核空间开关:打开
read
。而对于第二个,您需要 select
和 read
。然而,在大多数情况下,我认为大部分时间都花在等待数据或复制数据上。等待 read
或 select
并不重要。
使用共享内存,您需要处理同步问题。这“可能”会更快,但很复杂并且容易出错。如果您遇到严重的性能问题,您可以重新考虑这一点。 总之,我推荐第一种方法。扩展或重用也更容易。