netcat mit c++ bedienen
-
Also hast es schon recht gut beschrieben.
ich startet dsa c++ programm, welches mit myconsole eine konsole öffnet wo netcat gestartet wird. netcat lauscht dann an einem port und schreibt alles was an den port gesendet wird in eine text datei. Im endeffekt wird ein GPS tracker positionsdaten an den port senden. ich simuliere jetzt das den tracker in dem ich ein weiteres cmd fenster öffne und mit netcat fake gps daten an den port sende.mit dem c++ programm will ich nun die .txt datei in die die gps daten geschrieben werden auslesen. also die koordinaten in variablen packen um sie weiter verarbeiten zu können.
jetzt ist das problem, dass die gps daten erst in die txt datei kommen, wenn ich das fenster vom c++ programm schließe oder mit return(0); beende. also wenn ich die txt datei öffen, wenn das c++ fenster noch offen ist, bleibt die txt datei leer, erst wenn ich das fenster schließe, wird die datei vllt "refreshed" und die daten sind lesbar.
das ist ein problem^^ ist es so ungefähr klar?
-
Okay, das Problem habe ich glaube ich verstanden, warum das so ist, weiß ich nicht.
Es könnte aber sein, dass das Schreiben in die Datei nur deshalb beginnt, weil das zugehörige myConsole - Objekt zerstört wird. Wenn es Dich nicht stört, dass Du danach keine Kontrolle mehr über das gestartete netcat hast, könntest Du das ja mal versuchen, indem Du das myConsole - Objekt in einem Scope erzeugst, Deine Befehle an netcat absetzt, und dann den Scope verlässt und beobachtest, ob jetzt die Datei gefüllt wird.
-
Ich habe gerade einen kleinen Test gemacht:
Folgendes Testprogramm#include <windows.h> #include <iostream> using namespace std; int main() { while(++i < 1000000) { cout << "chrrrrrr ...\n"; Sleep(300); } }
via
mc.doCommand("test > test.txt");
gestartet und dann einfach mal abgewartet. Es ist nicht so, dass in die test.txt nicht geschrieben wird, es dauert einfach eine Weile, bis das Testprogramm seine Buffer mal flusht. Auch das Startprogramm lief noch, das myConsole - Objekt existierte noch, und nach einer ganzen Weile wurde die test.txt dann doch mal gefüllt. Vermutlich muss erst eine ganze Menge Daten zum Schreiben angefallen sein. Keine Ahnung, ob man das Buffer flushen von außen beeinflussen kann ...
-
hm wielange hat es denn bei dir gedauert? ich hab jetzt schonmal n paar mins gewartet und es ist trotzdem nichts in der txt datei erschienen. erst als ich das haupptfenster wieder geshclossen habe.
wie würde ich denn das myconsole objekt in einem scope erzeugen?
-
jasdefer schrieb:
hm wielange hat es denn bei dir gedauert? ich hab jetzt schonmal n paar mins gewartet und es ist trotzdem nichts in der txt datei erschienen. erst als ich das haupptfenster wieder geshclossen habe.
wie würde ich denn das myconsole objekt in einem scope erzeugen?
Mit meinem og Testprogramm wurde das erste Mal in die txt-Datei geschrieben, als etwa 350 Zeilen erzeugt waren.
Eine Variable in einem Scope erzeugen? Na, entweder in einer Funktion, oder so:
...
{
myConsole mc;
...
}Wenn die Funktion beendet wird, oder im obigen Fall die schließende Klammer erreicht wird, wird mc zerstört und der Destruktor aufgerufen.
Hat bei meinen Experimenten aber nix gebracht ...
-
ich hab auch noch einmal das programm ausgeführt und sehr viel text übertragen lassen. mehr als 350 zeilen. trotzdem wurde die txt datei nicht aktualisiert.
ach das ist mit scope gemeint. das habe ich auch noch einmal probiert, hat aber leider auch nicht funktioniert.
Fällt dir noch eine möglichkeit ein, wie man das Problem lösen könnte? Das würde mir sehr doll helfen
-
ach noch etwas interessantes. Wenn ich das netcat lauschen mit strg+c beende und das hauptfenster schließe wird die textdatei garnichtmehr aktualisiert. also wenn ich mit strg+c die verbindung beende, gehen die informationen die in die txt datei geschrieben werden sollen verloren
-
Ja, ist aber etwas mehr Aufwand. Du könntest zusätzlich zur Umleitung des StandardEingabeStroms auch noch den StandardAusgabeStrom umleiten. Ich habe für so einen Zweck vor kurzem eine Klasse im Konsolen-Forum vorgeschlagen, die habe ich auch als Vorlage für die hier gezeigt genommen.
Allerdings wird die für Deine Zwecke so nicht funktionieren, weil Dein netcat-Programm nicht zu Ende läuft, sondern weiter aktiv bleiben soll.
Du müsstest also ganz grob:
- eine zweite Pipe für die Umleitung des Standard-Ausgabe-Stroms erstellen
- das write-Handle dieser Pipe an den erzeugten Prozess (netcat) vererben
- und in Deinem Programm einen zweiten Thread starten, der sich um das Lesen/Verarbeiten der Ausgabe von netcat kümmert.Sieh Dir also nochmal die Klasse myConsole und die Klasse mySystem aus dem Konsolen-Forum an, versuch die Geschichte mit dem Umleiten der Standard-Eingabeströme zu recherchieren und zu verstehen, und sieh Dir an, wie das mit dem Thread funktioniert.
Wenn Du dann noch Detail-Fragen hast, stell sie ruhig hier. Ein schönes kurzes Beispiel für die Redirektion von STDIN und STDOUT gleichzeitig findest Du z.B. hier:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx
Allerdings brauchst Du für Deinen konkreten Fall wie gesagt einen zweiten Thread, obwohl, vielleicht geht es auch so, wenn Du zuerst Deine Befehle an netcat absetzt, und dann beginnst, den Output zu lesen und zu verarbeiten, ja, es hängt halt von den konkreten Anforderungen ab. Sieh Dir das Beispiel aus der MSDN an, vielleicht reicht Dir das schon, wenn Du es ein wenig anpasst.Edit:
Du würdest bei dieser Variante also keine Datei mehr schreiben, sondern die netcat-Ausgaben direkt in Deinem Hauptprogramm lesen.
-
okay, dann werde ich das mal probieren. vielen dank
ich guck mir das alles mal genauer an und versuhch die einzelnen schritte zu vertsehen
-
müsste ich, soweit ich das verstanden hab, dann im endeffekt zwei pipes haben. also pipe.h und pipe2.h zB. eben einmal für die umleitung der eingabgeströme eins und eins für die ausgabeströme?
-
Zwei Pipes ja, aber nicht pipe1.h und pipe2.h ...
Probier mal folgendes(pipe.h und pipe.cpp bleiben wie gehabt):
Das hab ich jetzt nur mal auf die Schnelle so hingerotzt, aber für das Testprogramm funktioniert es:#ifndef MYCONSOLEH #define MYCONSOLEH #include <string> #include "pipe.h" class myConsole { public: myConsole(); void doCommand(std::string command); std::string readFromProcess(); private: pipe writePipe; pipe readPipe; void startCommandProcess(HANDLE wrHandle, HANDLE rdHandle); }; #endif
#include <iostream> #include "myConsole.h" //public myConsole::myConsole() { writePipe.MakeInheritable(pipe::READ); readPipe.MakeInheritable(pipe::WRITE); startCommandProcess(readPipe.GetPipeHandle(pipe::WRITE), writePipe.GetPipeHandle(pipe::READ)); writePipe.ClosePipeHandle(pipe::READ); readPipe.ClosePipeHandle(pipe::WRITE); } void myConsole::doCommand(std::string command) { DWORD ignore; command.append("\n"); WriteFile(writePipe.GetPipeHandle(pipe::WRITE), command.c_str(), command.size(), &ignore, 0); } std::string myConsole::readFromProcess() { char inBuf[256]; DWORD nBytesRead = 0; std::string tmp; ReadFile(readPipe.GetPipeHandle(pipe::READ), inBuf, 256, &nBytesRead, NULL); return std::string(inBuf, nBytesRead); /* while(TRUE) { if (!ReadFile(readPipe.GetPipeHandle(pipe::READ), inBuf, 256, &nBytesRead, NULL) || !nBytesRead) break; for(int i = 0; i < nBytesRead; ++i) { if(inBuf[i] == 10) { result.push_back(tmp); tmp.clear(); } else if(inBuf[i] == 13) ; else tmp.push_back(inBuf[i]); } } */ } //private void myConsole::startCommandProcess(HANDLE wrHandle, HANDLE rdHandle) { PROCESS_INFORMATION pi; STARTUPINFO si; // Set up the start up info struct. ZeroMemory(&si,sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = rdHandle; si.hStdOutput = wrHandle; si.hStdError = wrHandle; // Use this if you want to hide the child: // si.wShowWindow = SW_HIDE; // Note that dwFlags must include STARTF_USESHOWWINDOW if you want to // use the wShowWindow flags. // Launch the process that you want to redirect (in this case, // Child.exe). Make sure Child.exe is in the same directory as // redirect.c launch redirect from a command line to prevent location // confusion. CreateProcess(NULL, "cmd", NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); // Close any unnecessary handles. CloseHandle(pi.hThread); CloseHandle(pi.hProcess); }
Testprogramm:
#include <iostream> #include <string> #include "myConsole.h" using namespace std; int main() { myConsole mc; //einige Kommandos absetzen, bei Dir zB "netcat ..." usw. mc.doCommand("dir"); mc.doCommand("ipconfig"); mc.doCommand("attrib"); //Ab hier die Ausgaben lesen und verarbeiten, hier werden sie einfach //via cout auf die Konsole geschrieben string str; do { str = mc.readFromProcess(); cout << str; }while(str.size()); }
Edit:
Nachteil bei dieser threadlosen Lösung ist, wenn der gestartet Prozess nichts mehr schreibt, bleibt das Programm in readFromProcess hängen.
-
Ich verstehe diese ganze Diskussion nicht. Die Lösung ist doch viel einfacher. Sie wurde hier auch schon erwähnt: einfach die Socket-API verwenden.
Netcat dient dazu, Daten über eine TCP-Verbindung zu schicken. Dazu gibt es eben die Socket-API. Da ich aber auf der Kommandozeile die API nicht direkt ansprechen kann, gibt es dieses Kommandozeilentool. Da ich in einem C++-Programm die API direkt ansprechen kann, macht es keinen Sinn, das Kommandozeilentool zu verwenden.
Prinzipiell sollte man im C++-Programmen wo immer möglich die API verwenden. Ein Kommandozeilentool aus einem C++-Programm aufzurufen, macht in den wenigsten Fällen Sinn.
Das gilt nicht nur für netcat sondern auch für die verwendeten Beispiele "dir", "ipconfig" oder "attrib".
-
vielen dank belli erstmal für den code, ich werde dsa ausporbieren sobald ich zeit habe
@ ich bins:
wie würde das denn mit dem ansprechen der api aussehen?
-
Es sieht noch immer so aus wie ich es auch schon am 11.05. hier gepostet habe^^:
Du könntest das ganze auch mit WIN Sock machen und ganz auf Netcat verzichten.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms738545(v=vs.85).aspx (Englisch)
Und da ich ebenfalls der Held von Google bin habe ich noch mehr Links für dich.
http://www.c-worker.ch/tuts.php (Deutsch, is aber C und kein C++ aber ist leich in C++ umzuändern. )
http://www.madwizard.org/programming/tutorials/netcpp/ (Englisch )( Auf der Seite nach ganz unten Scrollen und rechts steht dann "Networking introduction" und ab da gehts weiter. )
-
jasdefer schrieb:
vielen dank belli erstmal für den code, ich werde dsa ausporbieren sobald ich zeit habe
@ ich bins:
wie würde das denn mit dem ansprechen der api aussehen?Die Links von "Held vom MSDN !" beschreiben genau das. Und es gibt noch etliche andere Seiten, wo die Netzwerkprogrammierung erklärt wird.
-
Okay danke, ich gucke mir das noch einmal an. wenn das ganze einfacher als mit netcat ist, warum nicht^^
habe allerdings eine frage, ich benutzt dev-c++ als compiler und finde nirgends wie man folgenden punkte dort einstellen kann:
Ensure that the build environment refers to the Include, Lib, and Src directories of the Microsoft Windows Software Development Kit (SDK) or the earlier Platform Software Development Kit (SDK).
für visual hab ich was gefunden, allerdings nicht für dev-c++. wisst ihr wie man das hier macht?
-
@Belli:
Vielen Dank für deinen hingerotzen codeauch wenn die anderen sagen es wäre umständlich^^ egal. es scheint zu funktionieren. vielen dank dafür^^ ich gucke es mir weiter an.
Mit winsocket wäre es vllt noch etwas cooler, aber für mich jetzt viel mehr aufwand^^, falls das hier nicht funktionieren sollte, werde ich mir das mit winsocket nochmal angucken. euch auch vielen dank
-
Vielleicht ist es cooler mit Sockets ... aber wenn man da erst noch lernen muss, wie es funktioniert, ist das schon ein recht hoher Aufwand. Hinzu kommt, dass Du evtl. ja gar nicht weißt, was Dein netcat alles kann, und was Du dementsprechend alles nachprogrammieren musst.
Im übrigen hindert Dich ja niemand, das später noch nachzuholen oder zu versuchen. Die hier geposteten Klassen dienen erst mal dazu, auf einfache Weise jedes mögliche Programm, was sich über STDIN steuern lässt, anzusprechen und sind so in gewisser Weise universell einsetzbar.
Klar kann ich via WINAPI ein dir auch programmieren. Aber wenn ich die verschiedenen Optionen, die dir kann, alle nachbilden will, ist das auch eine Menge Arbeit.
Wenn das so für Dich erst mal funktioniert, freu ich mich, Dir geholfen zu haben!
-
ich habe nochmal einiges probiert, allerdings gibt es noch ein problem. also dass die ausgabe der konsole in dem string gespeichert wird ist super und funktioniert eigentlich. ich öffne netcat, dann zeigt er mir bei der ausgabe auch an netcat geöffnet etc. allerdings wenn ich jetzt den befehl sende, dass netcat an dem port lauschen soll, bleibt das programm einfach stehen. also es stürzt nicht ab, aber es führ auch keine weiteren schritte aus.
Ich hab jetzt mal den code und die ausgabe hinzugefügt. also wenn ich dein code richtig verstehe, speichert er im readfromprocess die ausgabe als char. kann es sein, dass das probleme bereit, wenn netcat quasi wartet?
#include <iostream>
#include <string>
#include "myConsole.h"using namespace std;
int main()
{
myConsole mc;
mc.doCommand("cd c:\\netcat");Sleep(5000);
string str;
str = mc.readFromProcess();cout << str;
cout << "\n\n Testausgabe 1\n";mc.doCommand("nc -L -v -p 9999");
Sleep(1000);
str = mc.readFromProcess();
cout << str;
cout << "\n\n Testausgabe 2\n";Sleep(1000);
str = mc.readFromProcess();
cout << str;
cout << "\nTestausgabe 3";cin.get();
}http://desmond.imageshack.us/Himg705/scaled.php?server=705&filename=ausgabeg.jpg&res=landing
(ach wenn man netcat manuell schließt, wird das programm weiter ausgeführt und testausgabe 3 ausgegeben.)
-
Belli schrieb:
[...]
Edit:
Nachteil bei dieser threadlosen Lösung ist, wenn der gestartet Prozess nichts mehr schreibt, bleibt das Programm in readFromProcess hängen.Ja, in der Methode readFromProcess wird gewartet, bis irgendwas vom gestarteten Prozess geschrieben wird, was hier auch gelesen werden kann. Gelesen wird mittels ReadFile, das ist eine blockierende Funktion, die erst zurückkehrt, wenn es auch Daten zu lesen gibt.
D.h., wenn netcat nichts mehr schreibt, gibt es für Dein Programm nichts mehr zu lesen und zu verarbeiten.