Forum: PC-Programmierung HTML mit dynamischem Inhalt


von Martin M. (martin69)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe einen Webserver mit ATmega128 gebaut (Rolladensteuerung). Der 
HTML-Code wird abhängig von diversen Parametern übertragen (Beispiel 
siehe Infoseite in der beigefügten Datei). Ich bin hierbei wie folgt 
vorgegangen:

1. "normale" HTML-Seite am PC zusammen gebastelt.
2. HTML-Datei in Einzelteile zerlegt, daß die zu ändernden Teile separat 
stehen (feste Teile im Flash, variable Texte im RAM).
3. Das Sammelsorium im AVR wieder (parameterabhängig) zusammen gebaut.

Funktioniert zwar, aber das ist ziemlich umständlich und die auch zuvor 
erforderliche Längenberechnung für den HTML-Header ist ziemlich lästig.

Besser wäre es, wenn man den String komplett im RAM zusammen bauen 
könnte, dann Länge des gesamten Strings mit strlen() herausfinden und 
dann den ganzen String senden. Dann wäre zumindest die Längenberechnung 
eine Kleinigkeit. Nachteil: ich hab nicht so viel RAM frei. Bin am 
überlegen, ob ich ein externes RAM ran mache.

Oder gibt es noch andere Tricks, wie man das machen könnte? Z.B. den 
HTML-Code komplett im Flash ablegen und an den variablen Stellen 
bestimmte Kennungen machen, die man dann während der Ausgabe auf der 
Schnittstelle modifiziert.

Bin für jeden Hinweis dankbar!

von Martin M. (martin69)


Angehängte Dateien:

Lesenswert?

anbei noch ein Auszug aus dem Quellcode zu dieser HTML-Datei. Ziemlich 
aufwändig das Ganze....

von Frank E. (Firma: Q3) (qualidat)


Lesenswert?

Kann es sein, dass du HTML und HTTP durcheinander bringst?

Der HTML-Code einer Webseite benötigt keine Längenangabe und hat auch 
keinen Header, wohl aber einen Head-Bereich. Bei HTTP wird dagegen 
tatsächlich eine Längenangabe benötigt ...

Ansonsten könnte deine Idee tatsächlich funktionieren. Du baust im 
HTML-Prototyp an den entsprechenden Stellen Platzhalter ein, die dann 
bei der Auslieferung durch die zutreffenden Werte ersetzt werden. Ich 
würde dafür ASCII-Zeichen oberhalb 128 verwenden. Weil die im HTML-Code 
sonst nicht vorkommen dürfen, kann man sie einfach ausfiltern.

Wegen der Längenangabe für den HTTP-Stream könntest du das Brett an der 
dünnsten Stelle bohren: ersetze alle Platzhalter immer durch die gleiche 
Anzahl von Zeichen, z.B. Nutzzeichen plus Leerzeichen oder 
HTML-Kommentare, so dass die Länge immer gleich bleibt - das spart die 
Berechnung.

Frank

von TestX .. (xaos)


Lesenswert?

auch wenns jetzt böse ist und kein standart etc ist...
sende deinen http header ohne length key.
wenn du alle daten gesendet hast schließt du den stream einfach zum 
browser ;) firefox oder ie, zumindest die neuen gehen dann von einer 
broken connection aus und nehmen die bisher empfangenen daten als 
content-length..

probiers aus ;)

von Martin M. (martin69)


Angehängte Dateien:

Lesenswert?

@Frank Esselbach:

ja, da hab ich wohl HTTP und HTML etwas durcheinander gebracht. Im 
Prinzip ist es mir schon klar, ich habe mich nur etwas unglücklich 
ausgedrückt...


@Andi D:

wie schließe ich einen Stream?


@alle
Das mit dem festen HTML-Code mit den Kennungen funktioniert auch nur bei 
einfacheren Seiten. Ist vielleicht nicht so eine gute Idee...

Ich habe auch Seiten, wo die HTML-Längen auch noch von anderen 
Parametern abhängig sind. So z.B. bei der Einblendung der Statusboxen im 
Grundriss (siehe Bild). Auf diesem Stockwerk sind es 13 Rolläden. Die 
selbe Funktion verwende ich derzeit für alle Stockwerke (wird mit 
Schleifen gemacht, abhängig von der Anzahl der Rolläden auf dem 
Stockwerk). Im Dachgeschoß sind es nur 7 Rolläden und daher auch 
entsprechend weniger HTML-Code... Z.B. gibt es die folgende Zeile, je 
nach dem, wie viele Rolläden vorhanden sind:

<div style="position:absolute; left:391px; top:55px; width:20px; 
height:20px; background-color:#FFFF00; border:2px solid #000000"></div>

Ich denke die einfachste Sache wird die mit dem externen RAM sein....

von oszi40 (Gast)


Lesenswert?

Klingt interessant, nur ist RAM bei Stromausfall ziemlich vergesslich.

von TestX .. (xaos)


Lesenswert?

socket.close() oder sowas in der richtung, kommt halt drauf an, was du 
als ethernet connection benutzt etc.

ich würde dir jetzt aber dazu raten, für etwas komplexere sachen solche 
spielerein mitm avr als webserver zu lassen...schön und gut für 
messwerte über ethernet etc ists ja ok aber nicht für ne GUI...
nimm am besten nen kleinen nettop oder sowas als sever mit linux, 
lighttpd, php, mysql und du wirst keinerlei probleme mehr haben, wobei 
sich gleichzeitig ganz neue welten an möglichkeiten eröffnen.

von Uhu U. (uhu)


Lesenswert?

Solche Geschichten kann man einigermaßen elegant mit einer einfachen 
Substitutions-Routine machen:

An die Stellen, an denen eine Variable eingefügt werden soll, schreibt 
man z.B. '$n' - ohne Hochkomma und n steht für die einstellige 
Parameterkennung.

Die Substitutions-Routine ist im Prinzip eine Kopier-Routine, die den 
Prototyptext zeichenweise in den Ausgabepuffer überträgt.

Wenn sie ein $ findet, testet sie das nächste Zeichen:

  - wenn es $ ist, wird ein $ in den Ausgabepuffer kopiert
  - wenn es eine gültige Parameterkennung ist, wird dessen Wert kopiert
  - anderenfalls wird $ gefolgt von der ungültigen Kennung kopiert

Anschließend wird nach dem $n weiter gemacht, bis irgendwann NUL kommt - 
das wird auch in den Ausgabepuffer übertragen und beendet.

Wenn ein $ ausgegeben werden soll, muß es verdoppelt werden.

Die Länge des Resultat-Strings kann man leicht mit strlen bestimmen...

von TestX .. (xaos)


Lesenswert?

Uhu Uhuhu wrote:

> Die Länge des Resultat-Strings kann man leicht mit strlen bestimmen...

genau dazu brauch man viel ram , der hier nicht verfügbar ist;)

von Uhu U. (uhu)


Lesenswert?

Du kannst den Urtext im Flash ablegen - dort wirst du mit der Methode 
viel Platz gewinnen, weil du das ganze
"uiLEN_html = uiLEN_html + strlen_P(FLASH_WEB_HTML_DOCTYPE);"-Gesprattel 
nicht mehr brauchst.

Zudem kannst du die Substitutions-Routine auch so schlau machen, daß sie 
die Länge als Nebenergebnis liefert.

Falls nicht genug RAM da ist, um den Text der endgültigen HTML-Seite im 
Speicher zu halten, kann man etwas mehr Zeit spendieren und zweimal 
substituieren:

- einmal in den Müll, um die Länge zu ermitteln und
- ein zweites mal direkt in den UART.

Diese Methode hat sogar den Vorteil, daß man das Längenfeld als 
$-Variable einfügen kann - man muß nur dafür sorgen, daß die Variable 
mit so vielen Stellen vorbesetzt ist, wie für das Längenfeld gebraucht 
wird.

Und zudem hat das Substitutionsverfahren einen ganz entscheidenen 
Vorteil: Es funktioniert datenunabhängig, d.h., wenn sich deine 
HTML-Seite ändert, brauchst du nur noch die Schablone zu ändern, nicht 
den ausführbaren Code.

Deswegen lieben Profis solche Methoden...

von G. O. (aminox86)


Lesenswert?

Für alle, die sich mit dynamischen Webseiten herumschlagen und es ganz 
genau wissen wollen (aber nicht zu fragen wagen):
-Jeremy Bentham: TCP/IP Lean. Webservers for embedded systems. CPM Books 
1.Auflage 2000, 2.Auflage 2002
Nach einer allgemeinen Einführung in (Internet)Übertragungsprotokolle 
und die Konstruktion eines TCP/IP-Stack wird gezeigt, wie interaktive, 
dynamische Webseiten unter anderem mit einem PIC erzeugt werden können. 
Beispielhaft sind dynamischer Text (eine Temperaturanzeige, was auch 
sonst) und dynamische Graphiken (Schalter mit Kontrolleuchten) 
dargestellt. Die zweite Auflage setzt noch eins drauf: Bildübertragung 
mit PIC über Ethernet zum PC.
Die Programmbeispiele, auch für den PIC, sind in C gehalten. Daher 
sollten sie sich leicht portieren lassen.
Meiner Meinung nach genau das Buch zum Thema.
mfg

von Simon K. (simon) Benutzerseite


Lesenswert?

Die Substitutionssache hat einen Nachteil bei dem bei kleinen 
Prozessoren benutzten Verfahren, wo immer nur ein Paket generiert und 
losgesendet wird:
Man muss diese Substitutionsroutine so schreiben, dass, wenn im 
aktuellen Paket nur noch 1 Byte frei ist, sie die restlichen Bytes beim 
nächsten mal rausschiebt. Ganz ohne extra RAM geht das also nicht.

von Uhu U. (uhu)


Lesenswert?

Es erfordert etwas mehr Hirnschmalz, ist aber auch machbar, wenn man die 
Substitutions-Routine so baut, daß immer maximal n Zeichen zurück gibt 
und in einer externen Variablen ihren Zustand abspeichert.

Noch speicherschonender geht es, wenn zunächst der Header von einer 
Steuerroutine auf den UART geht und dann die Substitution ihre nächsten 
n Zeichen direkt auf den UART ausgibt.

Was bleibt, ist das Substitutionsprinzip, das den Code von den Daten 
separiert.

von Martin M. (martin69)


Lesenswert?

danke für Eure Tipps!

von Rolf Magnus (Gast)


Lesenswert?

> Falls nicht genug RAM da ist, um den Text der endgültigen HTML-Seite
> im Speicher zu halten, kann man etwas mehr Zeit spendieren und
> zweimal substituieren:
>
> - einmal in den Müll, um die Länge zu ermitteln und
> - ein zweites mal direkt in den UART.

Dann muß man aber darauf achten, daß sich zwischendrin die zu 
substituierenden Werte nicht ändern. Wenn das nicht sicher ist, muß man 
deren zugrundeliegende Daten alle als Kopie sichern, damit man auch 
wirklich zweimal hintereinander den gleichen String bekommt.

von Martin M. (martin69)


Lesenswert?

ich werde wohl ein externes RAM auf den Webserver setzen. Am ATmega128 
kann man bis zu 60k x 8 anschließen.

1) HTML-String mit strcpy/strcat zusammen bauen und ins externe RAM 
legen
2) Länge des HTML-Strings mit strlen() bestimmen
3) HTTP-Header mit der LEN-Angabe samt HTML-String aus dem externen RAM 
senden

Fertig!

von (prx) A. K. (prx)


Lesenswert?

Simon K. wrote:

> Man muss diese Substitutionsroutine so schreiben, dass, wenn im
> aktuellen Paket nur noch 1 Byte frei ist, sie die restlichen Bytes beim
> nächsten mal rausschiebt. Ganz ohne extra RAM geht das also nicht.

Andersrum. Man kontrolliert vor der Substitution erst nach, ob genug 
Platz im Frame ist und schiebt den Kram erst einmal raus wenn nicht. Im 
nächsten Rutsch (Frame) hat man dann den ganzen Frame zur Verfügung.

Was HTTP angeht: Das funktioniert wie oben schon erwähnt wurde ganz gut 
auch ohne Länge.

von Simon K. (simon) Benutzerseite


Lesenswert?

A. K. wrote:
> Andersrum. Man kontrolliert vor der Substitution erst nach, ob genug
> Platz im Frame ist und schiebt den Kram erst einmal raus wenn nicht. Im
> nächsten Rutsch (Frame) hat man dann den ganzen Frame zur Verfügung.

Jup, das geht natürlich auch :-)

von Uhu U. (uhu)


Lesenswert?

Rolf Magnus wrote:
>> - einmal in den Müll, um die Länge zu ermitteln und
>> - ein zweites mal direkt in den UART.
>
> Dann muß man aber darauf achten, daß sich zwischendrin die zu
> substituierenden Werte nicht ändern. Wenn das nicht sicher ist, muß man
> deren zugrundeliegende Daten alle als Kopie sichern, damit man auch
> wirklich zweimal hintereinander den gleichen String bekommt.

Nein, man muß nur dafür sorgen, daß sich die Länge nicht ändert. Ob in 
einem Feld 0000 oder 4711 steht spielt keine Rolle.

von Uhu U. (uhu)


Lesenswert?

A. K. wrote:
> Andersrum. Man kontrolliert vor der Substitution erst nach, ob genug
> Platz im Frame ist und schiebt den Kram erst einmal raus wenn nicht. Im
> nächsten Rutsch (Frame) hat man dann den ganzen Frame zur Verfügung.

Nein. Wenn man die Protokollsteuerung von der Substitution entkoppelt 
und erstere der Substitutions-Maschine - die hat einen Zustand und weiß, 
wo sie bei jedem Aufruf weitermachen muß - sagt, wieviele Zeichen sie 
maximal in den Ausgabepuffer schreiben darf, dann kann man sich derlei 
vorausschauende Klimmzüge sparen.

Das einzige, was passieren kann, ist, daß die Substitutions-Maschine 
sagt, "es waren aber nicht 15, sondern nur noch 3 Zeichen auszugeben".

von Rolf Magnus (Gast)


Lesenswert?

> Nein, man muß nur dafür sorgen, daß sich die Länge nicht ändert. Ob
> in einem Feld 0000 oder 4711 steht spielt keine Rolle.

Wenn sich die Länge nicht ändert, weiß man sie schon zur Compilezeit und 
braucht sie nicht nachher zur Laufzeit berechnen.

von Uhu U. (uhu)


Lesenswert?

Rolf Magnus wrote:
> Wenn sich die Länge nicht ändert, weiß man sie schon zur Compilezeit und
> braucht sie nicht nachher zur Laufzeit berechnen.

Das ist nur ein Spezialfall. Die Länge kann sich ja auch dynamisch 
ändern, aber die Größenordnung ist jeweils vorab bekannt - nicht die 
genaue Größe.

von NexX (Gast)


Lesenswert?

Keine Ahnung, womit du den HTML-Code gemacht hast, aber den kann man 
schon um einiges kürzen... Damit wär dein RAM etwas entlastet...

von Martin M. (martin69)


Lesenswert?

@NexX:
mit Netscape Composer. jDer gibt relativ geringen HTML-Code aus (im 
Vergleich dazu, wenn man HTML mit Word erstellt).
Was will man da noch viel kürzer machen? Die Schrift möchte ich bei 
Arial lassen, denn sonst sieht die Seite nicht so schön aus... Sonst 
kann man ja quasi auf nichts verzichten...

Gruß
Martin

von Tobi H. (tobi-) Benutzerseite


Lesenswert?

CSS könnte hier Wunder wirken. Siehe
http://de.selfhtml.org/css/eigenschaften/schrift.htm#font

von Uhu U. (uhu)


Lesenswert?

Martin M. wrote:
> @NexX:
> mit Netscape Composer. jDer gibt relativ geringen HTML-Code aus (im
> Vergleich dazu, wenn man HTML mit Word erstellt).
> Was will man da noch viel kürzer machen? Die Schrift möchte ich bei
> Arial lassen, denn sonst sieht die Seite nicht so schön aus... Sonst
> kann man ja quasi auf nichts verzichten...

Das <font face="Arial,Helvetica">-Gesprattel muß nicht für jedes Element 
wiederholt werden.

Wenn du den Inhalt des Body in <font face="Arial,Helvetica"> ... </font> 
klammerst, reicht das aus - es sei denn, du willst unterwegs die Schrift 
ändern.

CSS braucht man deswegen nicht unbedingt...

von Martin M. (martin69)


Lesenswert?

@uhu:
das war ein sehr guter Tipp! Vielen Dank.

von Chris .. (nexx)


Lesenswert?

Ich hab den Code angepasst. Sollte in etwa aussehen wie vorher, ist aber 
kürzer und übersichtlicher:
1
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
2
<html>
3
<head>
4
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
5
<title>Server-Infos</title>
6
<style type="text/css">
7
body { font-family: Arial, Helvetica; background-color: #FFFF99; }
8
table { border: 0; width: 340px; background-color: #CCCCCC; margin-bottom: 40px;}
9
td { width: 140px; }
10
</style>
11
</head>
12
<body>
13
<h1>Infos Webserver</h1>
14
15
<table cols="2">
16
<tr><td><b>Hardware</b></td><td></td></tr>
17
<tr><td>Seriennummer:</td><td>Prototyp</td></tr>
18
19
<tr><td>Prozessor:</td><td>ATmega128</td></tr>
20
<tr><td>LAN-Interface:</td><td>XPORT Direct+</td></tr>
21
<tr><td>SD-Card:</td><td>ja</td></tr>
22
</table>
23
24
<table cols="2">
25
<tr><td><b>Software</b></td><td></td></tr>
26
<tr><td>Version:</td><td>001</td></tr>
27
28
<tr><td>Compiled:</td><td>Dec 26 2008 / 22:28:10</td></tr>
29
<tr><td>RS485-Adresse:</td><td>W30</td></tr>
30
</table>
31
32
<table cols="2">
33
<tr><td><b>Bautrate</b></td><td></td></tr>
34
<tr><td>RS485-Bus:</td><td>9600</td></tr>
35
<tr><td>AVR <=> XPort:</td><td>57600</td></tr>
36
37
</table>
38
39
<hr />
40
</body>
41
</html>

von Martin M. (martin69)


Lesenswert?

@Chris H.

oh ja, sieht im Internetexplorer aus wie meine Seite, im Quellcode aber 
übersichtlicher. Auch Dir vielen Dank!

Gruß
Martin

von NexX (Gast)


Lesenswert?

Man kann den Code noch weiter kürzen, aber dann ist er nicht mehr 
übersichtlich... Man würde nochmal ca 200 Byte sparen...
also alle zeilenumbrüche raus und noch einige andere änderungen im 
code...

von Martin M. (martin69)


Lesenswert?

die Zeilenumbrüche lasse ich lieber drin. Sonst blickt man nichts mehr, 
wenn man einen Fehler im HTML-Code sucht...

von NexX (Gast)


Lesenswert?

wenn der Code einmal kontrolliert ist und man danach die leerzeichen 
entfernt, und dann nur noch ersetzt, passiert nix...
selbst mit leerzeichen kann man noch ca 180 Byte einsparen..

von Uhu U. (uhu)


Lesenswert?

Such mal auf dem Web, da gibt es etliche HTML-komprimierende Programme - 
denen gibt man eine schön strukturierte Datei zu fressen und hinten raus 
kommt eine möglichst kurze, unschöne, die aber im Browser denselben 
Effekt hat.

Wenn du sowas in dein Buildscript einbaust, dann hast du als Quelltext 
deine übersichtliche Version und der Compiler büchst trotzdem die 
minimale ein.

von Simon K. (simon) Benutzerseite


Lesenswert?

Oder die Webseite als gz bereitstellen. Dann kannste aber nachher nur 
noch ganz schwer etwas einfügen ;)

von Nexx (Gast)


Lesenswert?

> Wenn du sowas in dein Buildscript einbaust, dann hast du als Quelltext
> deine übersichtliche Version und der Compiler büchst trotzdem die
> minimale ein.

dann ist aber immernoch die große version im speicher

von Uhu U. (uhu)


Lesenswert?

Nexx wrote:

> dann ist aber immernoch die große version im speicher

Wieso? Wenn das Packtool aus dem schon strukturieren Text einen 
Headerfile erzeugt, in dem der gepackte Text steht und der Quellmodul 
von diesem generierten Header abhängig ist, dann kommt hinten aus der 
Toolchain der Code mit dem gepackten HTML raus.

Ein make-Skript muß man dafür schon bauen...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.