J'essaye de combiner quelques programmes comme ça (veuillez ignorer les inclusions supplémentaires, c'est un travail en cours):
pv -q -l -L 1 < input.csv | ./repeat <(nc "host" 1234)
Où la source du programme répété se présente comme suit:
#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;
}
J'ai remarqué ceci:
- Quand j'utilise le tuyau
./repeat
, tout fonctionne comme prévu. - Lorsque j'utilise simplement la substitution de processus, tout fonctionne comme prévu.
- Lorsque j'encapsule pv en utilisant la substitution de processus, tout fonctionne comme prévu.
- Cependant, lorsque j'utilise la construction spécifique, je semble perdre des données (caractères individuels) de stdin!
J'ai essayé ce qui suit:
- J'ai essayé de désactiver la mise en mémoire tampon sur le canal entre
pv
et l'./repeat
utilisationstdbuf -i0 -o0 -e0
de tous les processus, mais cela ne semble pas fonctionner. - J'ai troqué epoll pour sondage, ça ne marche pas.
- Lorsque je regarde le flux entre
pv
et./repeat
avectee stream.csv
, cela semble correct. - J'avais l'habitude
strace
de voir ce qui se passait, et je vois beaucoup de lectures à un octet (comme prévu) et elles montrent également que des données manquent.
Je me demande ce qui se passe? Ou que puis-je faire pour enquêter davantage?
<(...)
? Y a-t-il une meilleure façon que<( 0<&- ...)
?<(... </dev/null)
. ne pas utiliser0<&-
: cela feraopen(2)
revenir le premier en0
tant que nouveau fd. Si vous lenc
supportez, vous pouvez également utiliser l'-d
option.epoll () ou poll () renvoyant avec E / POLLIN ne vous diront qu'un seul read () ne peut pas bloquer.
Ce n'est pas que vous puissiez faire beaucoup de lecture d'un octet jusqu'à une nouvelle ligne, comme vous le faites.
Je dis mai car un read () après epoll () retourné avec E / POLLIN peut toujours bloquer.
Votre code essaiera également de lire au-delà de l'EOF et ignorera complètement les erreurs de lecture ().
la source
repeat
programme traite essentiellement des données NMEA (basées sur des lignes et sans indicateur de longueur) provenant de plusieurs sources. Étant donné que je combine des données provenant de plusieurs sources en direct, j'aimerais que ma solution soit sans tampon. Pouvez-vous suggérer un moyen plus efficace de procéder?ypee
utilitaire qui lit à partir de plusieurs fds et les mélange dans un autre fd, tout en préservant les enregistrements (en gardant les lignes intactes).{ cmd1 & cmd2 & cmd3; } > file
fichier contiendra ce que vous décrivez. Cependant, dans mon cas, j'exécute tout depuis tcpserver (3), donc je veux également inclure stdin (qui contient les données client). Je ne sais pas comment faire ça.