Ich versuche, ein paar Programme wie dieses zu kombinieren (bitte ignorieren Sie alle zusätzlichen Includes, dies ist eine schwere Arbeit in Arbeit):
pv -q -l -L 1 < input.csv | ./repeat <(nc "host" 1234)
Wo die Quelle des Wiederholungsprogramms wie folgt aussieht:
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <string>
inline std::string readline(int fd, const size_t len, const char delim = '\n')
{
std::string result;
char c = 0;
for(size_t i=0; i < len; i++)
{
const int read_result = read(fd, &c, sizeof(c));
if(read_result != sizeof(c))
break;
else
{
result += c;
if(c == delim)
break;
}
}
return result;
}
int main(int argc, char ** argv)
{
constexpr int max_events = 10;
const int fd_stdin = fileno(stdin);
if (fd_stdin < 0)
{
std::cerr << "#Failed to setup standard input" << std::endl;
return -1;
}
/* General poll setup */
int epoll_fd = epoll_create1(0);
if(epoll_fd == -1) perror("epoll_create1: ");
{
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = fd_stdin;
const int result = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd_stdin, &event);
if(result == -1) std::cerr << "epoll_ctl add for fd " << fd_stdin << " failed: " << strerror(errno) << std::endl;
}
if (argc > 1)
{
for (int i = 1; i < argc; i++)
{
const char * filename = argv[i];
const int fd = open(filename, O_RDONLY);
if (fd < 0)
std::cerr << "#Error opening file " << filename << ": error #" << errno << ": " << strerror(errno) << std::endl;
else
{
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = fd;
const int result = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &event);
if(result == -1) std::cerr << "epoll_ctl add for fd " << fd << "(" << filename << ") failed: " << strerror(errno) << std::endl;
else std::cerr << "Added fd " << fd << " (" << filename << ") to epoll!" << std::endl;
}
}
}
struct epoll_event events[max_events];
while(int event_count = epoll_wait(epoll_fd, events, max_events, -1))
{
for (int i = 0; i < event_count; i++)
{
const std::string line = readline(events[i].data.fd, 512);
if(line.length() > 0)
std::cout << line << std::endl;
}
}
return 0;
}
Mir ist Folgendes aufgefallen:
- Wenn ich nur das Rohr benutze
./repeat
, funktioniert alles wie vorgesehen. - Wenn ich nur die Prozessersetzung verwende, funktioniert alles wie vorgesehen.
- Wenn ich pv mithilfe der Prozessersetzung einkapsele, funktioniert alles wie beabsichtigt.
- Wenn ich jedoch die spezifische Konstruktion verwende, scheine ich Daten (einzelne Zeichen) von stdin zu verlieren!
Ich habe folgendes versucht:
- Ich habe versucht, die Pufferung in der Pipe zwischen
pv
und./repeat
beistdbuf -i0 -o0 -e0
allen Prozessen zu deaktivieren , aber das scheint nicht zu funktionieren. - Ich habe Epoll gegen Umfrage getauscht, funktioniert nicht.
- Wenn ich mir den Stream zwischen
pv
und./repeat
mittee stream.csv
ansehe, sieht das richtig aus. - Früher
strace
habe ich gesehen, was los war, und ich sehe viele Einzelbyte-Lesevorgänge (wie erwartet), und sie zeigen auch, dass Daten fehlen.
Ich frage mich, was los ist? Oder was kann ich tun, um weitere Untersuchungen durchzuführen?
<(...)
? Gibt es einen schöneren Weg als<( 0<&- ...)
?<(... </dev/null)
. Verwenden Sie nicht0<&-
: es bewirkt , dass die ersteopen(2)
Rückkehr0
als neuen fd. Wenn Sie diesnc
unterstützen, können Sie die-d
Option auch verwenden .epoll () oder poll (), die mit E / POLLIN zurückkehren, sagen Ihnen nur, dass ein einzelnes read () möglicherweise nicht blockiert.
Nicht, dass Sie in der Lage wären, viele Ein-Byte-Lesevorgänge () bis zu einer neuen Zeile auszuführen, wie Sie es tun.
Ich sage vielleicht, weil ein read () nach epoll (), das mit E / POLLIN zurückgegeben wurde, immer noch blockieren kann.
Ihr Code versucht auch, nach EOF zu lesen, und ignoriert alle read () - Fehler vollständig.
quelle
repeat
Programm verarbeitet im Wesentlichen NMEA-Daten (zeilenbasiert und ohne Längenindikatoren) aus mehreren Quellen. Da ich Daten aus mehreren Live-Quellen kombiniere, möchte ich, dass meine Lösung ungepuffert ist. Können Sie einen effizienteren Weg vorschlagen, dies zu tun?ypee
Dienstprogramms, das aus mehreren fds liest und sie in ein anderes fd mischt, während Aufzeichnungen erhalten bleiben (Zeilen intakt bleiben).{ cmd1 & cmd2 & cmd3; } > file
Datei enthält das, was Sie beschreiben. In meinem Fall führe ich jedoch alles von tcpserver (3) aus, daher möchte ich auch stdin (das die Clientdaten enthält) einschließen. Ich bin mir nicht sicher, wie ich das machen soll.