Netcat - buforowanie

0

Witam!

Napisałem program, który zbiera pomiary a następnie wysyła je do klienta który się połączy na TCP/IP.

./main | nc -lk -p 5555

Program main zawiera taką pętle:

int value;
for(;;){
  value = measure(); // 1kHz
  printf("%d\n", value);
  fflush(stdout);
}

Klient łączy się w ten sposób:

nc adres_ip 5555

Niestety, gdy po jakimś czasie się połączę, dostaję ogromną ilość starych danych.
Czytałem o takim sposobie:

stdbuf -o0 -i0 ./main | stdbuf -o0 -i0 nc -lk -p 5555

Lecz dalej to samo.
Jak pozbyć się buforowania?

0

A czy ta twoja funkcje measure na pewno jest blokująca? Czy ona po prostu zmienia wartość z częstotliwością 1kHz? Bo jeśli ona nie blokuje to generujesz pakiety non stop i zwczajnie system nie wyrabia z ich wysyłaniem. Poza tym TCP w tym przypadku nie jest chyba najlepszym pomysłem, bo ma wbudowane mechanizmy opóźniające jeśli klient nie umie odbierać odpowiednio szybko no i retransmisje mogą cię tu blokować dodatkowo. Wydaje mi sie że UDP w tej sytuacji byłoby sensowniejsze.

0

Niestety, gdy po jakimś czasie się połączę, dostaję ogromną ilość starych danych.

Bo pierwszy netcat pisze na swój stdout, a w momencie kiedy podłączysz się drugim, dostaje on ten stdout.

Nie zrobisz tego co chcesz w taki sposób. "Buforowanie" które wyłaczyłeś działa w zupełnie inny sposób (dane nie są zatrzymywane, tylko wysyłane od razu - ale to kompletnie nie odnosi się do tego przypadku).

Sugeruję rozwiązać to po ludzku, czyli socketami - serwer nasłuchuje na jakimś porcie, i w momencie kiedy się podłączy klient zaczyna wysyłać do niego wiadomości - a jeśli żaden klient nie jest podłączony, nie wysyła żadnych wiadomości.

A czy ta twoja funkcje measure na pewno jest blokująca? Czy ona po prostu zmienia wartość z częstotliwością 1kHz? Bo jeśli ona nie blokuje to generujesz pakiety non stop i zwczajnie system nie wyrabia z ich wysyłaniem.

To nie to, po prostu łączy się do serwera który wysyła mu całe historyczne dane

Poza tym TCP w tym przypadku nie jest chyba najlepszym pomysłem, bo ma wbudowane mechanizmy opóźniające jeśli klient nie umie odbierać odpowiednio szybko no i retransmisje mogą cię tu blokować dodatkowo. Wydaje mi sie że UDP w tej sytuacji byłoby sensowniejsze.

Nie dawaj ludziom takich pomysłów, bo później słuchają. Poza - czasami - gamedevem i innymi rzeczami realtime nie widziałem jeszcze własnego protokołu opartego na UDP (stworzonego przez zwykłą firmę, a nie trzy komitety i dwie korporacje) gdzie użycie UDP było uzasadnione.

0

Dzięki, czyli z nc nie dam rady takiego czegoś zrobić?
Nie chcę integrować serwera do programu, ponieważ bardzo wygodnie mi jest strumień kierować np. do pliku czy do innego programu.
Jeśli nc nie ma takiej możliwości, będę musiał napisać jego kopię uwzględniając brak buforowania danych w przypadku gdy nie ma połączenia.

0

program:

#include <unistd.h>
#include <fcntl.h>

int measure(int value){
	sleep(1);
	return value+1;
}

int main(int argc,char **argv){

	fcntl(0,F_SETFL,fcntl(0, F_GETFL, 0) | O_NONBLOCK);
	int value = 0;
	char c;
	for(;;){
	  value = measure(value);
	  if(read(0, &c,1)){
	    if(c == '1'){
	      printf("%d\n",value);
	      fflush(stdout);
	    }
	  }
	}
}
 

serwer:
nc -lp 5555 -c ./a.out
client:

$ nc localhost 5555
2
1
7
1
9
1
17
1
32 
0

Program ma zczytywać wartości z czujników i wypluwać je na stdout, to jest jego zadanie, nie mogę implementować dodatkowych wygibasów.

0

No to można utworzyć cały serwer, np w rubym:

#!/usr/bin/ruby
require 'socket' 
serw = TCPServer.new('localhost', 5555)

var = 0
file = File.open(0)

thread = Thread.new do
  while true
    var = file.gets
  end
end

while true
  s = serw.accept
  req = s.gets
  res = "#{var}\n"
  
  s.print      "HTTP/1.1 200 OK\r\n" +
               "Content-Type: text/plain\r\n" +
               "Content-Length: #{res.bytesize}\r\n" +
               "Connection: close\r\n" +
               "\r\n"

  s.print res
  s.close
end

 

uruchamiać tak:
./a.out | ./skrypt.rb
i widzisz wszystko w przeglądarce:
localhost:5555

1 użytkowników online, w tym zalogowanych: 0, gości: 1