Saya mencoba untuk menggabungkan beberapa program seperti itu (abaikan semua tambahan, ini adalah pekerjaan berat yang sedang berjalan):
pv -q -l -L 1 < input.csv | ./repeat <(nc "host" 1234)
Di mana sumber dari program berulang terlihat sebagai berikut:
#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;
}
Saya perhatikan ini:
- Ketika saya hanya menggunakan pipa
./repeat
, semuanya berfungsi sebagaimana mestinya. - Ketika saya hanya menggunakan proses substitusi, semuanya berfungsi sebagaimana dimaksud.
- Ketika saya merangkum pv menggunakan proses substitusi, semuanya berfungsi sebagaimana dimaksud.
- Namun, ketika saya menggunakan konstruksi spesifik, saya tampaknya kehilangan data (karakter individu) dari stdin!
Saya sudah mencoba yang berikut ini:
- Saya telah mencoba untuk menonaktifkan buffering di antara
pv
dan./repeat
menggunakan pipastdbuf -i0 -o0 -e0
pada semua proses, tapi itu sepertinya tidak berhasil. - Saya telah bertukar epoll untuk polling, tidak berhasil.
- Ketika saya melihat aliran antara
pv
dan./repeat
dengantee stream.csv
, ini terlihat benar. - Saya biasa
strace
melihat apa yang sedang terjadi, dan saya melihat banyak bacaan single-byte (seperti yang diharapkan) dan mereka juga menunjukkan bahwa data akan hilang.
Saya bertanya-tanya apa yang sedang terjadi? Atau apa yang bisa saya lakukan untuk menyelidiki lebih lanjut?
<(...)
? Apakah ada cara yang lebih baik daripada<( 0<&- ...)
?<(... </dev/null)
. jangan gunakan0<&-
: itu akan menyebabkan yang pertamaopen(2)
kembali0
sebagai fd baru. Jika Andanc
mendukungnya, Anda juga dapat menggunakan-d
opsi ini.epoll () atau polling () yang dikembalikan dengan E / POLLIN hanya akan memberi tahu Anda bahwa satu pembacaan () mungkin tidak mencekal.
Bukan berarti Anda akan dapat melakukan banyak membaca satu byte () hingga baris baru, seperti yang Anda lakukan.
Saya katakan mungkin karena read () setelah epoll () dikembalikan dengan E / POLLIN masih dapat memblokir.
Kode Anda juga akan mencoba membaca EOF yang lalu, dan sepenuhnya mengabaikan kesalahan read ().
sumber
repeat
Program saya pada dasarnya memproses data NMEA (berbasis garis dan tanpa indikator panjang) dari berbagai sumber. Karena saya menggabungkan data dari berbagai sumber langsung, saya ingin solusi saya tidak terbaca. Bisakah Anda menyarankan cara yang lebih efisien untuk melakukan ini?ypee
utilitas yang membaca dari beberapa fds dan mencampurkannya ke fd lain, sambil menjaga catatan (menjaga garis tetap utuh).{ cmd1 & cmd2 & cmd3; } > file
File akan berisi apa yang Anda gambarkan. Namun, dalam kasus saya, saya menjalankan semuanya dari tcpserver (3), jadi saya ingin memasukkan stdin (yang berisi data klien) juga. Saya tidak yakin bagaimana melakukan itu.