Hallo zusammen,
nach welchen Schlagworten muss ich suchen, wenn ich unter Linux eine
nicht blockierende (Server-)Anwendung schreiben möchte: Konkret: auf dem
Raspberry PI soll eine Anwendung laufen, mit der remote über ein
Socket-Interface die Stati der Eingänge ausgelesen werden können.
Kann ich alles in eine Endlosschleife schmeißen, auf dem Port lauschen
und der Scheduler erledigt den Rest?
Gruß
Dennis
Edit: Interessant wäre auch noch wie man "Starter-Skripte" realisiert,
in der Form:
Dennis S. schrieb:> nach welchen Schlagworten muss ich suchen, wenn ich unter Linux eine> nicht blockierende (Server-)Anwendung schreiben möchte: Konkret: auf dem> Raspberry PI soll eine Anwendung laufen,
Linux Daemon
> mit der remote über ein> Socket-Interface die Stati der Eingänge ausgelesen werden können.
Unix Socket Programming Howto oder so ähnlich
> Kann ich alles in eine Endlosschleife schmeißen, auf dem Port lauschen> und der Scheduler erledigt den Rest?
So ähnlich
> Edit: Interessant wäre auch noch wie man "Starter-Skripte" realisiert,> in der Form: ./appl status> ./appl start> ...> Einfach über "argv"?
Ja, auswerten über argc/argv.
siehe z.B. BusyBox.
Moin,
google mal nach "tutorial linux network programming" und suche Dir eines
heraus, was Dir zusagt. Ohne Tutorial wirst Du nicht weit kommen.
Ansonsten man pages zu poll oder epoll, listen, connect, read, write
usw. lesen.
Als Buch ist Richard Stevens "Unix Network Programming" zu empfehlen, da
didaktisch sehr gut, für den Einstieg, je nach Kenntnisstand, aber
vielleicht etwas erschlagend.
Das Starter Skript ist erstmal Dein geringstes Problem, aber status und
start sind nicht Parameter Deiner Anwendung, die wohl mehr im
Hintergrund als daemon laufen wird (siehe man page daemon), sondern des
Skriptes.
Hier empfiehlt sich auch Richard Stevens 'Advanced Programming in the
Unix System Environment', das auch Daemon Prozesse und alles um
Unix/Linux Systeme gut erklärt. Wirst Du langfristig brauchen, wenn Du
effiziente Server Prozesses schreiben willst.
In eine Endlosschleife kann man alles 'schmeißen', macht man aber nicht
mehr so (siehe epoll, schon erwähnt).
In diesem Sinne,
frohes Schaffen.
Kaj schrieb:> Welche Sprache solls denn sein? C? Python? node.js? php? Ruby?
Ich war mir sehr sicher den "C"-Filter hier aktiviert zu haben, scheint
aber nicht geklappt zu haben. Also: C!
> Wie waers mit "linux non blocking server"?
Danke, aber sehr allgemein.
> Nein , macht er nicht. Du musst schon selbst dafuer sorgen, dass das> ganze nicht blockiert, einfach das non-blocking flag nutzen...
Dann habe ich wohl das Konzept vom Scheduler nicht verstanden: warum
kann ein präemptiver Scheduler (der in Linux ja wohl vorhanden ist)
plötzlich nur noch arbeiten wenn die Applikationen kooperativ ist?
> Was soll das sein?
Siehe mein erklärendes Beispiel.
Vielen Dank an alle für die Literatur-Hinweise. Das wird mir
weiterhelfen!
Gruß
Dennis
Der Rest wird schon noch weiterlaufen, aber in einer pollenden
Endlosschleife hast Du permanent 100% CPU Last und das ist im
Allgemeinen nicht besonders effizient.
Thorsten schrieb:> aber in einer pollenden> Endlosschleife hast Du permanent 100% CPU Last und das ist im> Allgemeinen nicht besonders effizient.
Darum: (e)"poll" oder den Vorgänger "select" verwenden.
Das verlagert das Warten auf Netzwerk-Ereignisse in den Kernel, 0%
CPU-Last solange nichts zu tun ist.
Oder du forkst bei jeder neuen Verbindung, und verwendest innerhalb des
geforkten Childs Blocking IO.
Die Fork-Lösung ist m.M.n viel einfacher (zu verstehen).
Macht halt schnell schlapp, wenn viele hundert Clients gleichzeitig was
wollen.
Beispiel (von
http://www.cs.ucsb.edu/~almeroth/classes/W01.176B/hw2/examples/tcp-server.c):
Dennis S. schrieb:> Ich war mir sehr sicher den "C"-Filter hier aktiviert zu haben, scheint> aber nicht geklappt zu haben. Also: C!
Der wirkt nur auf die Threadliste/Suche → "Zeige alles mit dem
Buchstaben 'C' im Titel"
T.roll schrieb:> Der wirkt nur auf die Threadliste/Suche → "Zeige alles mit dem> Buchstaben 'C' im Titel"
Danke für den Hinweis, dessen war ich mir nicht bewusst!
Planlos schrieb:> Thorsten schrieb:>> aber in einer pollenden>> Endlosschleife hast Du permanent 100% CPU Last und das ist im>> Allgemeinen nicht besonders effizient.>> Darum: (e)"poll" oder den Vorgänger "select" verwenden.> Das verlagert das Warten auf Netzwerk-Ereignisse in den Kernel, 0%> CPU-Last solange nichts zu tun ist.> Oder du forkst bei jeder neuen Verbindung, und verwendest innerhalb des> geforkten Childs Blocking IO.>> Die Fork-Lösung ist m.M.n viel einfacher (zu verstehen).> Macht halt schnell schlapp, wenn viele hundert Clients gleichzeitig was> wollen.
Deswegen hat der liebe Gott die Threads erfunden. Der Nachteil dabei
ist, daß der Requesthandler dabei im Adressraum des Hauptprogramms
abläuft und Programmierfehler dann nicht mehr nur den einen
Requesthandler, sondern das ganze Programm und alle seine Subthreads
bedrohen. Diesen Nachteil hat aber auch die Lösung mit select(2),
poll(2) oder epoll(7); deswege würde ich die fork(2)-Lösung bevorzugen,
wenn keine hohe Last erwartet wird.
Wie man Startskripte erstellt, hängt vom Betriebssystem beziehungsweise
vom verwendeten Init-System ab. Für das SystemV-Init von Debian-Systemen
gibt es üblicherweise eine Vorlage in /etc/init.d/skeleton, das übliche
Techniken zur Realisierung eines solchen Skripts demonstriert und als
Basis für eigene Implementierungen dienen kann.
In diesem Zusammenhang sollte man sich außerdem anschauen, wie man ein
Programm zu einem Daemon macht: Abkoppeln vom Parentprozess und Starten
einer eigen Prozessgruppe, Abkoppeln vom kontrollierenden Terminal, und
das Wechseln zu einer anderen Benutzer- und Gruppenid mit set(e)uid(2)
und set(e)gid(2). Für einige dieser Aufgaben kennen manche Systeme den
Befehl daemon(3), oder das Kommandozeilenprogramm daemon(1) aus dem
Paket daemon, welches auf der libslack-Bibliothek basiert.
Also was willst Du jetzt in einer funktionierenden Linux Umgebung den
Webserver "pimpen" oder selber was coden ?
Wenn Du schon Linux mit z.B. Apache hast kannst Du via CGI beliebige
Programme nutzen (Sicherheit mal außen vor).
Wenn's "sicher" sein soll weil DMZ bau Dir selber ein Programm das via
SSL/TLS auf einem im RFC nicht genannten Port Deine Signale liefert.
Geht auch via PHP, JAVA & Co.
Wenn Du kein Feedback/Kontrolle brauchst wäre es wohl am sinnvollsten
einfach ein HTML auf der Serverseite zu bauen und anzuzeigen ...
haeh schrieb:> Also was willst Du jetzt in einer funktionierenden Linux Umgebung den> Webserver "pimpen" oder selber was coden ?> Wenn Du schon Linux mit z.B. Apache hast kannst Du via CGI beliebige> Programme nutzen (Sicherheit mal außen vor).> Wenn's "sicher" sein soll weil DMZ bau Dir selber ein Programm das via> SSL/TLS auf einem im RFC nicht genannten Port Deine Signale liefert.> Geht auch via PHP, JAVA & Co.> Wenn Du kein Feedback/Kontrolle brauchst wäre es wohl am sinnvollsten> einfach ein HTML auf der Serverseite zu bauen und anzuzeigen ...
Nur um ein paar GPIOs zu exponieren, sind Apache/CGI/PHP/Java/HTTP/HTML
wohl mit schwerer Artillerie auf unbewaffnete Haussperlinge geschossen,
zumal der OP ja selbst nach einem schlichten Socket-Interface fragt.
Mir ist eben eingefallen, daß so ein Linux ja bereits eine ausgesprochen
komfortable Möglichkeit für so etwas dabei hat, nämlich den guten alten
Inetd. Der kümmert sich nicht nur darum, das richtige Programm zu
starten, sondern auch um die gesamte Netzwerkkommunkation.
Der Ablauf ist dann: der inetd lauscht auf einem Port auf Verbindungen.
Wenn ein Client eine solche aufbaut, startet inetd das für diesen Port
konfiguierte Programm und übergibt ihm die auf dem Socket empfangenen
Daten (so vorhanden) via STDIN. Und alles, was das Programm auf STDOUT
oder STDERR schreibt, schickt inetd über den Socket zum Client zurück.
Als Protokoll auf Applikationsebene bietet sich hier das
leichtgewichtige JSON an. Dafür gibt es kleine Parser für jede relevente
Programmiersprache und zudem ist das auch von Menschen gut lesbar (think
debugging!). Und das in eine Webseite oä. einzubinden, ist dank AJAX ein
Kinderspiel.
Sheeva P. schrieb:> Mir ist eben eingefallen, daß so ein Linux ja bereits eine ausgesprochen> komfortable Möglichkeit für so etwas dabei hat, nämlich den guten alten> Inetd.
Interessante Möglichkeit! Das werde ich mal ausprobieren.
Gruß
Dennis
Sheeva P. schrieb:> Nur um ein paar GPIOs zu exponieren, sind Apache/CGI/PHP/Java/HTTP/HTML> wohl mit schwerer Artillerie auf unbewaffnete Haussperlinge geschossen,> zumal der OP ja selbst nach einem schlichten Socket-Interface fragt.
Eines davon läuft aber heutzutage sowieso schon, also warum noch wie vor
100 Jahren mit C auf Sockets rumzuwerkeln? Zudem geht die Entwicklung
mit Webtechnologien viel schneller und einfacher von der Hand. Sockets
in C? Das mache ich nur noch wenn ich nen schmallbrüstigen MC habe und
selbst dort sind die Zeiten für sowas vorbei, die Turnaroundzeiten
gehen mit embeddedlinux und den entspr. Webapplikationen viel schneller.
Zudem kann ich das alles auf einem PC entwickeln und wenns fertig ist
einfach rüberkopieren, samt Konfig und entspr. Updatefunktionen, da muss
ich nicht mal was kompilieren.
> Mir ist eben eingefallen, daß so ein Linux ja bereits eine ausgesprochen> komfortable Möglichkeit für so etwas dabei hat, nämlich den guten alten> Inetd. Der kümmert sich nicht nur darum, das richtige Programm zu> starten, sondern auch um die gesamte Netzwerkkommunkation.
inetd ist eine wandelnde Dauersicherheitslücke und deshalb meist per
default deaktiviert oder gar nicht mehr installiert. Das war schon
seiner Zeit nur ein übler Hack, das nutzt zu recht keiner mehr.
Zudem hat man oft schnell weitere Anforderungen:
Datenbankschnittstellen, Email, Webservices von anderen Webservern,...
geht alles mit zeitgemässer Webtechnologie. Da fummelst du dich mit
Sockets in C zu Tode.
> Als Protokoll auf Applikationsebene bietet sich hier das> leichtgewichtige JSON an. Dafür gibt es kleine Parser für jede relevente> Programmiersprache und zudem ist das auch von Menschen gut lesbar (think> debugging!). Und das in eine Webseite oä. einzubinden, ist dank AJAX ein> Kinderspiel.
Und wenn man auf dem Server schon ein entspr. Webtechnologie einsetzt
muss man sich nicht mal gross mit JSON von Hand befassen, da gibts
komfortable Generatoren, Parser,... sogar schon in der Datenbank. Das
fummelt heute keiner mehr selber zusammen und schon gar nicht auf
Lowlevelebe mit Sockets, in C, nicht mal HTTP fasst man heute noch
direkt an. Wir sind nicht mehr in den 90ern.
Dennis S. schrieb:> Edit: Interessant wäre auch noch wie man "Starter-Skripte" realisiert,
Bei jeder guten Linux-Distri findest Du eine Datei /etc/init.d/skeleton
die als Vorlage für eigene Start-Scripte dienen soll.
Das klappt auch beim Raspi.
Thomas schrieb:> Bei jeder guten Linux-Distri findest Du eine Datei /etc/init.d/skeleton> die als Vorlage für eigene Start-Scripte dienen soll.
Seit systemd ist das nicht mehr so selbstverständlich. Darin ist
/etc/init.d nur noch eine historische Altlast.
A. K. schrieb:> Seit systemd ist das nicht mehr so selbstverständlich. Darin ist> /etc/init.d nur noch eine historische Altlast.
Korrekt.
Bei meinem Raspi ist aber noch init.d angesagt.
elowolo schrieb:> inetd ist eine wandelnde Dauersicherheitslücke
Nicht der inetd ist das Problem, sondern was reingehängt wird. Einfach
nur eine /bin/sh bringt gewisse Probleme mit sich. ;-)
elowolo schrieb:>> Mir ist eben eingefallen, daß so ein Linux ja bereits eine ausgesprochen>> komfortable Möglichkeit für so etwas dabei hat, nämlich den guten alten>> Inetd. Der kümmert sich nicht nur darum, das richtige Programm zu>> starten, sondern auch um die gesamte Netzwerkkommunkation.> inetd ist eine wandelnde Dauersicherheitslücke und deshalb meist per> default deaktiviert oder gar nicht mehr installiert. Das war schon> seiner Zeit nur ein übler Hack, das nutzt zu recht keiner mehr.
Also der xinetd ist mir jetzt nicht als sicherheitstechnisch besonders
problematisch aufgefallen:
http://www.cvedetails.com/vendor/473/Xinetd.html
Ich finde die Idee den zusammen mit einem kleinen Skript zu verwenden
eigentlich gar nicht schlecht. Ist natürlich nicht besonders performant,
aber dafür sehr schnell fertig, ohne daß ich mich groß um Dinge wie
Non-blocking I/O, Threads oder forken kümmern muss. Und der Serverdienst
für SysV-Init oder systemd ist auch schon fertig konfiguriert.
So kommt auch jemand, der sich mit diesen ganzen Techniken noch nicht so
auskennt, schnell zum Ziel.
Wenn ich diese Aufgabe lösen müsste, würde ich es aber wahrscheinlich
ganz in Python machen und keinen inetd verwenden.
Sheeva P. schrieb:> In diesem Zusammenhang sollte man sich außerdem anschauen, wie man ein> Programm zu einem Daemon macht: Abkoppeln vom Parentprozess und Starten> einer eigen Prozessgruppe, Abkoppeln vom kontrollierenden Terminal, und> das Wechseln zu einer anderen Benutzer- und Gruppenid mit set(e)uid(2)> und set(e)gid(2). Für einige dieser Aufgaben kennen manche Systeme den> Befehl daemon(3), oder das Kommandozeilenprogramm daemon(1) aus dem> Paket daemon, welches auf der libslack-Bibliothek basiert.
Den ganzen hokuspokus kann man sich mit systemd sparen. Man lässt sich
von systemd starten, der kümmert sich darum, dass man als richtiger
Benutzer läuft, die Ausgaben im Log landen, etc.
http://0pointer.de/public/systemd-man/daemon.html
elowolo schrieb:> Eines davon läuft aber heutzutage sowieso schon, also warum noch wie vor> 100 Jahren mit C auf Sockets rumzuwerkeln? Zudem geht die Entwicklung> mit Webtechnologien viel schneller und einfacher von der Hand.
Webtechnologien sind ganz nett, aber nicht die Antwort auf die Frage.
Ich selbst würde für sowas wahrscheinlich Python mit dem Flask-Framework
benutzen, das bringt alles Nötige (inklusive Webserver) schon fertig
mit, wenn ich denn auf Webtechnologien setzen will. Oder wenn es ganz
schnell und klein werden soll, würde ich C++ mit Webtoolkit benutzen.
Aber hier waren Sockets gefragt. Da gibt es für Python ein wunderbares,
extrem komfortables Framework namens SocketServer, der direkt Threading
und ein paar andere Schmankerln mitbringt. Und wenn es ganz schnell und
klein werden soll, benutze ich C++11 und Boost::ASIO, das hat ebenfalls
alles gleich mit dabei.
Du siehst: ich kenne da eine ganze Reihe von Möglichkeiten, mit denen
ich selbst sowas umsetzen würde. Aber C++, Python, und Webtechnologien
waren hier allesamt nicht gefragt.
> inetd ist eine wandelnde Dauersicherheitslücke und deshalb meist per> default deaktiviert
Weder, noch. Wenn man es richtig macht, sind inetd (und xinetd) für
solche Aufgaben immer noch prima geeignet.
> Datenbankschnittstellen, Email, Webservices von anderen Webservern,...> geht alles mit zeitgemässer Webtechnologie. Da fummelst du dich mit> Sockets in C zu Tode.
Darum geht es hier aber nicht. Ich weiß auch nicht, wo Dein Problem ist,
ich arbeite schon lange mit Sockets in C und diversen anderen Sprachen,
und hatte es dabei noch nie nötig, mich "zu Tode" zu "fummeln".
> Und wenn man auf dem Server schon ein entspr. Webtechnologie einsetzt> muss man sich nicht mal gross mit JSON von Hand befassen, da gibts> komfortable Generatoren, Parser,...
Vielen Dank für Deine Belehrungen, aber daß es für JSON kleine Parser
gibt, hatte ich selbst schon geschrieben, als ich JSON als Datenformat
vorgeschlagen habe. Aber nur, um ein paar GPIOs per JSON zu exponieren,
braucht man keinen Generator -- so etwas ist mit "printf("{'gpio1': %d,
'gpio2': %d}, ...);" schneller von Hand geschrieben als Du eine passende
Library gefunden hast.