• Hallo liebe Userinnen und User,

    nach bereits längeren Planungen und Vorbereitungen sind wir nun von vBulletin auf Xenforo umgestiegen. Die Umstellung musste leider aufgrund der Serverprobleme der letzten Tage notgedrungen vorverlegt werden. Das neue Forum ist soweit voll funktionsfähig, allerdings sind noch nicht alle der gewohnten Funktionen vorhanden. Nach Möglichkeit werden wir sie in den nächsten Wochen nachrüsten. Dafür sollte es nun einige der Probleme lösen, die wir in den letzten Tagen, Wochen und Monaten hatten. Auch der Server ist nun potenter als bei unserem alten Hoster, wodurch wir nun langfristig den Tank mit Bytes vollgetankt haben.

    Anfangs mag die neue Boardsoftware etwas ungewohnt sein, aber man findet sich recht schnell ein. Wir wissen, dass ihr alle Gewohnheitstiere seid, aber gebt dem neuen Board eine Chance.
    Sollte etwas der neuen oder auch gewohnten Funktionen unklar sein, könnt ihr den "Wo issn da der Button zu"-Thread im Feedback nutzen. Bugs meldet ihr bitte im Bugtracker, es wird sicher welche geben die uns noch nicht aufgefallen sind. Ich werde das dann versuchen, halbwegs im Startbeitrag übersichtlich zu halten, was an Arbeit noch aussteht.

    Neu ist, dass die Boardsoftware deutlich besser für Mobiltelefone und diverse Endgeräte geeignet ist und nun auch im mobilen Style alle Funktionen verfügbar sind. Am Desktop findet ihr oben rechts sowohl den Umschalter zwischen hellem und dunklem Style. Am Handy ist der Hell-/Dunkelschalter am Ende der Seite. Damit sollte zukünftig jeder sein Board so konfigurieren können, wie es ihm am liebsten ist.


    Die restlichen Funktionen sollten eigentlich soweit wie gewohnt funktionieren. Einfach mal ein wenig damit spielen oder bei Unklarheiten im Thread nachfragen. Viel Spaß im ngb 2.0.

Java - Prozess Output lesen

Impact

NGBler

Registriert
14 Juli 2013
Beiträge
155
Hey ihr ;)

Mein Plan ist es, mit Java einen Prozess (in Linux) zu starten und den kontinuierlichen Output des Prozesses dann zu verarbeiten, Zeile für Zeile.
Ansich hört es sich nicht schwierig an (ist es bestimmt auch nicht), jedoch schaffe ich es aktuell einfach nicht an den Output des Prozesses zu kommen. Ich habe mit Hilfe des ProzessBuilders den Prozess ausgeführt und dieser läuft. Der nächste Schritt für mich wäre es jetzt, den Output (der ja eigentlich kontinuierlich in unregelmäßigen Abständen auf der Konsole ausgegeben wird) zu verarbeiten und je nach Output irgendwas zu triggern.

Doch wie kann ich den kontinuierlichen Output lesen?

Ich habe bereits beim ProcessBuilder die Methode redirectOutput(new File(xyz)) ausgeführt, so dass ich sehen konnte, das der Prozess wirklich ausgeführt wird und Output erzeugt. Das klappt auch prima! Doch ich möchte nun nicht den Output in eine Datei schreiben, den Output dann Zeile für Zeile aus der Datei holen und dann darauf reagieren, sondern ich möchte es ohne diesen Zwischenschritt der Datei lösen. Das muss doch irgendwie machbar sein, oder?!

Ich freue mich über Tipps! :) :beer:
 

Larius

OutOfOrder

Registriert
12 Juli 2013
Beiträge
5.792
Was genau hast du vor? Eventuell kann man eine einfachere Lösung finden.
 

Impact

NGBler

Registriert
14 Juli 2013
Beiträge
155
  • Thread Starter Thread Starter
  • #3
Naja, im Prinzip habe ich genau das vor, was ich beschrieben habe.

Es geht darum Whatsapp (mit yowsup) auf dem PI am Laufen zu haben und auf eingehende Nachrichten zu reagieren. Wie genau darauf reagiert wird bzw. was gemacht werden soll habe ich mir noch nicht überlegt, auf jeden Fall müssen dazu aber die eingehenden Nachrichten, welche aktuell auf der Konsole ausgegeben werden, irgendwie geparst werden.

yowsup selbst ist in Python geschrieben und theoretisch könnte man sicherlich auch da direkt ansetzen. Jedoch habe ich mit Python bislang wenig Erfahrung gemacht und wollte eigentlich auch unabhängig von yowsup bleiben.
Es kann ja nun eigentlich wirklich nicht so schwer sein vernünftig an den Output zu gelangen...

Theoretisch würde es ja sogar funktionieren den Output direkt über die Datei zu nehmen (mittels des redirect-Aufrufs am ProcessBuilder), doch im Endeffekt habe ich dann eine unnötige Datei, welche sogar im Laufe der Zeit größer und größer wird.
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.667
@Imp4c

Dann würde ich doch bei yowsup ansetzen und die Ausgabe an eine Datei anfügen, ist die Ausgabe größer als X Zeilen oder der letzten geparsten Nachricht, so leerst du diese wieder.
Du bräuchtest dann nur einen Kontrollmechanismus der sicherstellt das du die Daten die gerade geschrieben worden sind auch wirklich verarbeitet hast...

In Python kann man aber auch gut die Dateiattribute wie letzte Änderung und letzten Zugriff mittels "os.stat(pfad)" ermitteln.

Funktioniert in Python 2.x wie auch in Python 3.

-----

Ich bin ja nicht wirklich ein Linux Guru, aber das Umleiten der Konsolenausgabe in eine Datei mittels "> MeineDatei.txt" würde nicht funktionieren?
Du mußt dann aber immer noch "sicherstellen" das die Datei dann irgendwann gelöscht wird, damit diese nicht ins unermeßliche anwächst....

Ich würde es aber als leichter ansehen und auch effektiver direkt in yowsup diese Test einzubauen bzw. dann auch in Java. Da hast du vermutlich etwas mehr Kontrolle wie und wann und wo die Dateien erstellt werden. Es hätte dann sogar den Vorteil das du yowsup vom weiteren Parsen (wenn nicht gethreaded) blocken könntest, bevor der input (aufgrund des letzten Zugriffs) nicht oder noch nicht vearbeitet wurde.

Es gibt in Python auch die Möglichkeit eine "tmpfile" erstellen zu lassen, das gelöscht wird so bald nichts mehr darauf verweist, wenn die Anwendung ordentlich geschlossen wird. (os.tmpfile)
 

Rakorium-M

NGBler

Registriert
14 Juli 2013
Beiträge
413
Die ProcessBuilder-Dokumentation meint: Lass redirectOutput() weg (PIPE ist Standard) und nutz anschließend Process.getInputStream(). Über diesen Stream solltest du wie üblich die Ausgabe des Prozesses lesen können.
Einen InputStream zeilenweise einlesen kannst du bspw. über einen BufferedReader lösen (new BufferedReader(new InputStreamReader(...))), der müsste eine readLine()-Methode haben.
Falls die Ausgabe auf stderr (statt stdout) erfolgt, musst du analog Process.getErrorStream() nutzen.
 

Impact

NGBler

Registriert
14 Juli 2013
Beiträge
155
  • Thread Starter Thread Starter
  • #6
Danke für die Beiträge bisher.

Ich denke ich konnte das Problem etwas eingrenzen, allerdings noch nicht lösen.

Ich habe nun die Ausgabe so umgebogen (mit redirectOutput(newFile(xyz)), so dass diese nicht auf der Console angezeigt wird, sondern in eine Datei geschrieben wird. Das funktioniert auch, allerdings steht die komplette Ausgabe erst nach Beendigung des Programms in der Datei - sie wächst also nicht live (wie es allerdings die Consolenausgabe des Prozesses tut - Zeile für Zeile). Wie kann das sein?

Kann es sein, dass alle bisher ausprobierten Reader (LineNumberReader, BufferedReader, dieses redirectOutput) auf ein bestimmtes Zeichen am Ende einer Zeile warten, bis diese irgendwas erkennen? Beim BufferedReader in der Doku von readLine() steht folgendes:
Reads a line of text. A line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed.

Das bedeutet ja, dass wenn die Line niemals mit \n oder \r beendet ist, die Methode immer null zurück gibt. Mh, komisch alles.

@theSplit:
Natürlich würde es dann irgendwann mehr Sinn machen das alles schon in Python in eine Datei zu schreiben und nur noch diese dann aus Java zu öffnen. Ich habe jedoch gedacht es geht eben auch "eleganter" und ohne den Umweg über die Datei. Ich hatte mir den Flow so vorgestellt:
yowsup(Python) -> Console -> Java parst Console Zeile für Zeile
und nicht
yowsup(Python) -> speichern in Datei -> Java -> öffnen der Datei und Zeile für Zeile parsen
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.667
Ich habe nun die Ausgabe so umgebogen (mit redirectOutput(newFile(xyz)), so dass diese nicht auf der Console angezeigt wird, sondern in eine Datei geschrieben wird. Das funktioniert auch, allerdings steht die komplette Ausgabe erst nach Beendigung des Programms in der Datei - sie wächst also nicht live (wie es allerdings die Consolenausgabe des Prozesses tut - Zeile für Zeile). Wie kann das sein?

Mal eine Vermutung in den Raum geworfen:
Kann es sein das die Ausgabe des Prozesses erst "final" (zum bearbeiten/speichern/weiterverarbeiten) wird nachdem der Prozess wirklich als "Beendet" gekennzeichnet ist?
Schließlich weiß kein Programm ab welchem Zeitpunkt die Ausgabe wirklich abgeschlossen worden ist. Ein Newline ist kein "\0" Terminator eines Strings und die Zeichenkette/Konsolen Ausgabe, gilt nicht als beendet. :unknown:

Vielleicht wäre es leichter den Python Code als separaten Prozess periodisch zu starten, beenden zu lassen und den Output dann zu verarbeiten? Ist natürlich bei einer zeitkritischen Anwendung (weil sollte ja Live passieren) kein wirklich schlaues vorgehen, aber vielleicht ginge es dann den Output mitzuschneiden da in sich abgeschlossen?

Ich hab auch mal selbst danach gesucht, habe dabei aber auch keine Antwort auf meiner Vermutung erhalten, jedoch einen mehr "unix like" way gefunden:
http://stackoverflow.com/questions/7360473/linux-non-blocking-fifo-on-demand-logging
 

Brother John

(schein)heilig
Veteran

Registriert
1 Aug. 2013
Beiträge
235
Dateien schreiben ist normalerweise gepuffert. Neuer Inhalt wird in der Datei erst dann periodisch sichtbar, wenn der Puffer vollläuft und in die Datei gespült wird. Wie groß der Puffer ist, hängt von der jeweiligen Implementierung ab.

Der saubere Ansatz ist allerdings das, was Rakorium-M sagt: ohne Datei über getInputStream().
 
Zuletzt bearbeitet:

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.667
@Brother John

Kannst du da etwas zu meiner "Theorie" sagen? - Mir ist es nicht ganz nachvollziehbar wann der Hauptprozess gemeldet bekommt wenn ein Kind Prozess wirklich alle Daten geschrieben/ausgegeben hat. Um beim Threading zu bleiben. Oder geht das Output -> Processing in einem Abwasch nachdem eine Zeile "abgeschlossen" wurde, so das der Hauptthread oder jede andere Anwendung ein "Daten wurden geschireben", weiter zur Verarbeitung, Signal bekommen kann?

Der Hauptprozess weiß doch nie wann der Subprozess aufgehört Daten zu schreiben, weil nicht beendet?
Oder wird auf eine Newline gewartet was als abgeschlossen gilt?
 
Zuletzt bearbeitet:

Rakorium-M

NGBler

Registriert
14 Juli 2013
Beiträge
413
Ich würde mal tippen, dass die Dateiausgabe gebuffert wird, um nicht für jedes einzelne Byte die Festplatte anzuwerfen. Daten werden also erst geschrieben, wenn bspw. 4KB Text angekommen sind, oder eben der Stream geschlossen wird (bspw. weil das Programm sich beendet). Wenn da wirklich nur einzelne Nachrichten ankommen kann es natürlich eine Weile dauern, bis die 4KB (oder wie viel auch immer) voll sind...
 

Impact

NGBler

Registriert
14 Juli 2013
Beiträge
155
  • Thread Starter Thread Starter
  • #11
Ich habe heute wenig Zeit und schreibe morgen nochmal ausführlicher etwas dazu mit Codebeispiel.

getInputStream() habe ich natürlich schon versucht zu nutzen - ohne Erfolg.

Aktuell löse ich es jetzt so:
Ich schreibe bei jeder eingehenden Nachricht den Empfänger und die dazugehörige Nachricht in eine Datei (nennen wir sie messages.msg). Diese Datei öffne ich dann in Java mit Hilfe des LineNumberReader() und gehe Zeile für Zeile durch die Datei. Wenn ich bei der letzen Zeile angekommen bin prüfe ich jede Sekunde, ob eine neue Zeile hinzugekommen ist und falls ja gehts von vorne los.
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.667
Und wie löst du das anwachsen der Datei auf X kb/MB ? - Wann weiß die Java Anwendung das neue Daten vorhanden sind?
Und wann fängt das Python Skript bei null an?

Würde mich interessieren wie du das gelöst hast.
 

Brother John

(schein)heilig
Veteran

Registriert
1 Aug. 2013
Beiträge
235
@theSplit
Das Prinzip ist bei Dateien und Konsolenausgabe dasselbe, weil i.d.R. beides gepufferte Streams sind. D.h. der Elternprozess kann immer dann neue Ausgaben sehen, wenn der Kindprozess seinen Ausgabepuffer spült. Wann das passiert, ist abhängig von der Implementierung im Kind. Eine maximale Puffergröße gibts immer. Bei textorientierten Streams löst außerdem oft ein Zeilenumbruch die Spülung aus. Zwingend ist das aber nicht unbedingt. Es sei denn, der Programmierer des Kinds löst explizit ein Spülen aus.

Beispiel: Bei den C++-iostreams ist '\n' ein simpler Zeilenumbruch.
Code:
std::cout << "Hello, world!\n";
spült vielleicht, oder auch nicht.
Code:
std::cout << "Hello, world!" << std::endl;
dagegen ist ein Zeilenumbruch + garantierte Spülung.

So ähnlich ist das auch in Python:
Code:
print("Hello, world!")
hat einen Zeilenumbruch am Ende, erzwingt aber keine Spülung. Das braucht ab Python 3
Code:
print("Hello, world!", flush=True)
oder alternativ (auch Python-2-kompatibel)
Code:
print("Hello, world!")
sys.stout.flush()

Du hast recht, dass der definitv endgültige Jetzt-kommt-nix-mehr-Zeitpunkt der Tod des Kindprozesses ist. Wenn der regulär beendet wurde – und sauber programmiert ist – wird er beim Sterben auch nochmal spülen, sodass sämtliche Ausgaben für den Elternprozess sichtbar werden. Wenn er dagegen hart terminiert, kann es durchaus sein, dass einige Ausgaben verloren gehen, weil die noch im Puffer hängen und nicht mehr rausgeschrieben werden.

@Imp4c
Was genau klappt denn bei getInputStream() nicht? Ich hab vor ein paar Tagen erst damit rumgetestet und problemlos Python stdout und sterr per getInputStream() auf die Java-Konsole gekippt. Wenn du erst in Java in eine Datei umleitest und das funktioniert, hast du jedenfalls keine Spülprobleme. Wenn der Pythonprozess die Daten zu spät oder in zu großen Happen liefert, würde sich das auf die umgeleitete Datei genauso auswirken.
 

Impact

NGBler

Registriert
14 Juli 2013
Beiträge
155
  • Thread Starter Thread Starter
  • #14
Also, ich habe das aktuell so gelöst:

yowsup wird gestartet und bei eingehenden Nachrichten wird die Nachricht und der Empfänger sowohl auf der Konsole ausgegeben, als auch in eine Datei geschrieben.

[src=python]def onTextMessage(self,messageProtocolEntity):
text_file = open("messages_py.msg", "a")
text_file.write('from:'+messageProtocolEntity.getFrom(False)+'\n')
text_file.write('text:'+messageProtocolEntity.getBody()+'\n')
text_file.close()

print("from:%s" % (messageProtocolEntity.getFrom(False)))
print("text:%s" % (messageProtocolEntity.getBody()))[/src]

Die Ausgabe auf der Konsole sieht dann so aus:
from:4912345
text:hallo
from:4998765
text:hallo zurück

Das Java-Programm öffnet nun diese Datei und liest sie bis zum Ende ein. Am Ende angekommen wird eine Sekunde gewartet und anschließend geprüft, ob neue Zeilen zum parsen vorhanden sind. Dies löse ich wie folgt:
[src=java]
FileReader messageFileReader = null;
try {
messageFileReader = new FileReader("messages_py.msg");
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
LineNumberReader lnr = new LineNumberReader(messageFileReader);
while (p.isAlive()) {
try {
String line = lnr.readLine();
if (line == null) {
Thread.sleep(1000);
continue;
}
String[] from = line.split(":");
line = lnr.readLine();
String[] content = line.split(":");
// z.B System.out.println(content[1]);
}
[/src]

Darüber, dass die Datei zu groß wird, habe ich mir bislang noch keine Gedanken gemacht. Ich könnte mir aber vorstellen, dass ich die Zeile aus der Datei lösche sobald sie abgearbeitet wurde. Bei dem geringen Nachrichtenverkehr bislang müsste ich aber wohl einige Jahre warte bis die Datei ein paar MB groß ist :D

@Brother John
Tja, was genau da nicht klappt kann ich dir gar nicht sagen. Es hapert auf jeden Fall an der Stelle, an der der BufferedReader readLine() auf dem inputStream ausführen soll. readLine() gibt nämlich immer null zurück, egal ob was auf der Konsole ausgegeben wurde oder nicht.
Sobald ich das Programm allerdings mit STRG-C abschieße, werden (manchmal, aber nicht immer!) noch kurz ein paar Zeilen ausgegeben.
Evtl. hilft es ja wenn ich in python noch zusätzlich sys.stdout.flush() ausführe?:unknown:
 

Brother John

(schein)heilig
Veteran

Registriert
1 Aug. 2013
Beiträge
235
Das klingt schon nach einem Spülproblem. Probiers mal mit flush() und schau, ob sich was ändert.
 
Oben