Forum: PC-Programmierung .NET einfachster HTTP-Server gefragt


von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Hallo zusammen,

um von einer Android-App etwas per HTTP-Request in einer Datenbank zu 
speichern, möchte ich per VS.NET HTTP-Requests bearbeiten.

Was mich zunächst wundert: Wie kann man einen HttpListener vernünftig 
beenden? Ich frage mich, ob es der richtige Weg ist mit
"Catch ex As System.Net.HttpListenerException":
1
Console.WriteLine("Terminated Listener1Worker.")
2
Return ' MainWindow_Closing - is this the best way?

Beim Beenden des Programms (MainWindow_Closing) wird tatsächlich 
ausgegeben:
> HttpListener Abort()
> Terminated Listener1Worker.


Hier der gesamte Quelltext, sorry für VB statt C#:
1
Imports ST = System.Text
2
Imports SCM = System.ComponentModel
3
Imports SN = System.Net
4
Class MainWindow
5
    Private WithEvents Listener1Worker As New SCM.BackgroundWorker()
6
    Private Listener1 As SN.HttpListener = Nothing
7
    Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
8
        If Not SN.HttpListener.IsSupported Then
9
            Console.WriteLine("HttpListener is not supported on this platform.")
10
        Else
11
            Listener1Worker.WorkerReportsProgress = True
12
            Listener1Worker.WorkerSupportsCancellation = True
13
            Listener1Worker.RunWorkerAsync()
14
        End If
15
    End Sub
16
    Private Sub Listener1Worker_DoWork(sender As Object, e As SCM.DoWorkEventArgs) Handles Listener1Worker.DoWork
17
        Listener1 = New SN.HttpListener() 'Using Listener1 = New SN.HttpListener()
18
        Listener1.Prefixes.Add("http://+:8008/")
19
        Listener1.Start()
20
        Do While Not Listener1Worker.CancellationPending
21
            Dim context As SN.HttpListenerContext = Nothing
22
            Try
23
                context = Listener1.GetContext()
24
            Catch ex As System.Net.HttpListenerException
25
                If ex.ErrorCode = 995 Then 'Der E/A-Vorgang wurde wegen eines Threadendes oder einer Anwendungsanforderung abgebrochen
26
                    Console.WriteLine("Terminated Listener1Worker.")
27
                    Return ' MainWindow_Closing - is this the best way?
28
                Else
29
                    Stop
30
                End If
31
            Catch ex As Exception
32
                Stop
33
            End Try
34
            If context Is Nothing Then
35
                Stop
36
            Else
37
                Console.WriteLine("request: {0}", context.Request.Url)
38
                Dim responseText As String = "<html><body>Hello from HttpListener.</body></html>"
39
                Dim buff As Byte() = ST.Encoding.UTF8.GetBytes(responseText)
40
                With context.Response
41
                    .ContentType = "text/html"
42
                    .StatusCode = 200  ' HTTP "OK"
43
                    .ContentLength64 = buff.Length
44
                    .OutputStream.Write(buff, 0, .ContentLength64)
45
                    .OutputStream.Close()
46
                End With
47
            End If
48
        Loop
49
        Listener1.Stop()
50
        Listener1.Abort() 'End Using
51
    End Sub
52
    Private Sub MainWindow_Closing(sender As Object, e As SCM.CancelEventArgs) Handles Me.Closing
53
        If Listener1 IsNot Nothing Then
54
            Console.WriteLine("HttpListener Abort().")
55
            Listener1.Stop()
56
            Listener1.Abort()
57
        End If
58
    End Sub
59
End Class

Außerdem finde ich die Zeilen
1
    .ContentLength64 = buff.Length
2
    .OutputStream.Write(buff, 0, .ContentLength64)
irgendwie redundant und daher doof. Geht das irgendwie schlauer? Also: 
Gibt es was "Fertiges" für den Fall, dass man nur einen einzigen Stream 
hat?

: Bearbeitet durch User
von Horst (Gast)


Lesenswert?

Du weißt aber schon, dass Windows auf einem Server nichts zu suchen hat?

von Peter II (Gast)


Lesenswert?

Horst schrieb:
> Du weißt aber schon, dass Windows auf einem Server nichts zu suchen hat?

wie ein der Keine Ahnung hat das es auch Windows-Server gibt.

Unabhängig davon gibt es auch Mono unter Linux.

Torsten C. schrieb:
> Was mich zunächst wundert: Wie kann man einen HttpListener vernünftig
> beenden?

https://msdn.microsoft.com/de-de/library/system.net.httplistener(v=vs.110).aspx
in der Doku steht Close();

ein catch beendet doch kein Programm, sondern fängt eine Execption ab. 
Irgendwie verstehe ich den VB code nicht.


https://msdn.microsoft.com/de-de/library/system.net.httplistener(v=vs.110).aspx
hier ist doch ein Beispiel drin, dort wird es auch richtig beendet.

von c-hater (Gast)


Lesenswert?

Torsten C. schrieb:

> um von einer Android-App etwas per HTTP-Request in einer Datenbank zu
> speichern, möchte ich per VS.NET HTTP-Requests bearbeiten.

Schon der Ansatz ist ziemlicher Unsinn. Ein Riesen-Umweg, der nur unter 
Benutzung von 'zig unnötigen und hochkomplexen Software-Schichten 
funktioniert. Zwar scheinbar irgendwie "modern", aber letztlich doch 
vollkommen idiotisch...

Nein, man sagt besser einfach der DB direkt, was sie tun soll und fertig 
ist der Lack. Ist auch nur 'ne TCP-Verbindung und ein bissel Austausch 
von sehr wenig und obendrein weitgehend problemlos menschenlesbarem Text 
über diese Verbindung. Und ja: das geht sogar auch mit Android, der so 
ziemlich schlimmsten Fehlentwicklung seit der Erfindung von 
Betriebsystemen und APIs überhaupt...

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Zur Exception
=============

Peter II schrieb:
> hier ist doch ein Beispiel drin, dort wird es auch richtig beendet.

Ich will den Listener vom Server aus stoppen, ohne auf einen Request zu 
warten

Peter II schrieb:
> Irgendwie verstehe ich den VB code nicht.

Wegen "einfach" wollte ich "lines of code" sparen und nutze oben die 
synchrone Methode in einem BackgroundWorker:
1
context = Listener1.GetContext()

> ein catch beendet doch kein Programm, sondern fängt eine Execption ab.

Ja, das ist auch so: Erst kommt die Ausgabe "HttpListener Abort()", 
danach "Terminated Listener1Worker."

Also: Wenn ich den Listener1 mit Close() oder Abort() beende, kommt die 
Exception. Close() und Abort() machen hier keinen Unterschied.

Für den einfachen Server reicht es eigentlich, wenn immer nur ein 
Request zur Zeit bearbeitet wird, daher dachte ich, ich kann den ganzen 
Async- und Task-Overhead sparen.

Für mich sieht es so aus:
Entweder man lebt mit dieser Exception oder man nutzt die asynchrone 
Methode:
1
context = Listener1.GetContextAsync()
Also wie hier: http://stackoverflow.com/a/13710086

Listener starten und stoppen:
http://stackoverflow.com/a/16949790

Es sind dann mehr "lines of code", dafür gibt es keine unschöne 
Exception bei Close(). Mein Ansatz scheint ein missglückter Spar-Versuch 
zu sein. Oder hat noch jemand eine Idee, wie das mit dem 
BackgroundWorker ohne Exception geht?


Zum Thema DB direkt
===================

c-hater schrieb:
> Nein, man sagt besser einfach der DB direkt, was sie tun soll und fertig
> ist der Lack.

Das habe ich so noch nie gemacht, da muss ich mal ganz dumm fragen:

Du meinst also eine "client-server database". Damit fällt SQLite z.B. 
schon mal aus, richtig?

Es geht um den Beitrag "Re: Akku-Lader mit Datenbank"
Ein Tablet oder ein Handy sollen als "Bedienteil" auf die DB zugreifen 
und ein ESP8266 z.B. auch. Die DB läuft im "proof of concept" noch auf 
einem Windows-PC, später z.B. auf einem RasPi.

Mit "einfach besser der DB direkt sagen" ändert sich doch die 
Schnittstelle, wenn ich zwischen Windows und RasPi wechsle, oder?
Bei HTTP-Requests kann ich die Schnittstelle (bis auf die IP-Adresse) 
überall gleich halten. Oder gibt es auch eine einheitliche Schnittstelle 
für Client-Server Datenbanken?

: Bearbeitet durch User
von R. R. (elec-lisper)


Lesenswert?

Horst schrieb:
> Du weißt aber schon, dass Windows auf einem Server nichts zu suchen hat?

Ich stimme dir zu. Aber irrwitzigerweise gibt es Bereiche, in denen 
Linux scheinbar garnicht existiert. Die wenigsten unserer Kunden (von 
Industrie bis zum Agrarbetrie) haben etwas anderes als Windows auf ihren 
Servern.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Nette Diskussion. Ein Grund mehr, warum das Betriebsystem auf die 
Schnittstelle zwischen Clients und Server keinen Einfluss haben sollte.

Aktuell komme ich mit dem o.g. Mini-HTTP-Server (incl. Exception beim 
Beenden) ganz gut zurecht. Natürlich muss ich später für den RasPi 
nochmal so einen HTTP-Service programmieren.

Darüber, wie man unabhängig vom Betriebsystem direkt per TCP/IP mit 
einer "client-server database" spricht, finde ich irgendwie keine Infos.

c-hater schrieb:
> Schon der Ansatz ist ziemlicher Unsinn.

Wie würdest Du das denn machen?

Zu komplex darf es nicht sein: Vielleicht ist sogar HTTP schon unnötig 
komplex und ich baue besser was proprietäres?

Zur Erinnerung:
Clients sind hier ein ESP8266 und eine Android-App als "Bedienteil".

Für einen ESP8266 muss auch erst alles programmiert werden. Es gibt 
jedoch fertige MQTT- oder HTTP-Routinen für den ESP8266. JDBC habe ich 
auf einem ESP8266 nicht.

: Bearbeitet durch User
von bluppdidupp (Gast)


Lesenswert?

Torsten C. schrieb:
> Natürlich muss ich später für den RasPi
> nochmal so einen HTTP-Service programmieren.

Wieso? HttpListener sollte auch mit mono auf dem RasPi laufen ;D

von JojoS (Gast)


Lesenswert?

Da lohnt sich vielleicht der Blick auf JavaScript und Node.js, da ist so 
ein Listener mit ein paar Zeilen erledigt und die Portierung auf den 
Raspi ist ein copy. Bei uns in der 4ma fahren selbst alte C++/C# 
Verfechter völlig auf JS ab und wollen nix anderes mehr machen.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

c-hater schrieb:
> man sagt besser einfach der DB direkt, was sie tun soll und fertig
> ist der Lack.

Nochmal: Wie geht das? Immer, wenn ich versuchen will, das heraus zu 
finden, steht da: Mach das per "API-Layer", "WEB-Service" oder sonstwas.

Z.B. hier:
https://www.quora.com/What-are-the-best-ways-to-connect-an-Android-app-to-a-MySQL-database
> A direct connection between android and MySql is not possible …
Oder hier:
http://www.androidhive.info/2012/05/how-to-connect-android-with-php-mysql/
> 5. Connecting to MySQL database using PHP

Für mich sieht das so aus, als wenn "c-hater" hier nur trollen wollte.

JojoS schrieb:
> Da lohnt sich vielleicht der Blick auf JavaScript und Node.js

Hmmm, von "Node.js" habe ich auch schon viel gutes gehört, habe es nur 
nie ausprobiert. Das schaue ich mir mal genauer an. Danke. :-)

Kann man in "Node.js" auch MQTT-Server ansprechen? Das würde die 
Synchronisation zwischen Bedienteilen und ESP8266-Knoten deutlich 
verbessern, da man damit auch "pushen" kann. Im einfachsten Fall z.B. 
den Zeitpunkt der letzten Änderung einer Tabelle.

von Jojo S. (Gast)


Lesenswert?

node.js ist eine Basis für die es unzählige Erweiterungen (Module) gibt, 
MQTT ist kein Problem:
https://www.npmjs.com/package/mqtt
Man muß sich nur mit dieser JavaScript Sprache anfreunden.

von Kaj (Gast)


Lesenswert?

Da hier ja node.js schon erwähnt wurde, werf ich einfach noch Python in 
den Raum. Ein Script und es funktioniert sowohl unter Linux als auch 
Windows.

Die einfachste Art einen HTTP-Server zu starten ist mit Python3 auf der 
Konsole einfach ein:
1
python -m http.server 8000 --bind 127.0.0.1
Bumm, schon hast du lokal einen Server der auf Port 8000 lauscht. 
Befindet sich in dem Ordner, aus dem du heraus den Server startest, eine 
index.html, so wird diese ausgeliefert, wenn du mit deinem Browser 
localhost:8000 besuchst.

Für den ESP8266 gibt es MicroPython:
https://github.com/micropython/micropython/tree/master/esp8266#micropython-port-to-esp8266

Für MQTT gibt es ein fertiges Python-Package.
https://pypi.python.org/pypi/paho-mqtt

von T.roll (Gast)


Lesenswert?

Peter II schrieb:
> das es auch Windows-Server gibt.

Es gibt viel Mist auf der Welt, das heißt aber nicht das man es auch 
benutzen soll. Windows Server ist sowas wie "WLAN-Kabel".
Ob die auch Windows Server anbieten? → http://etel-tuning.eu/

Die meisten Angriffe was ich auf meine Server verzeichne, suchen 
übrigens nach Windows Server. Das sagt schon mehr als genug...

Robin R. schrieb:
> Die wenigsten unserer Kunden (von
> Industrie bis zum Agrarbetrie) haben etwas anderes als Windows auf ihren
> Servern.

Das Problem hierbei ist aber ein anderes. Auf der einen Seite die 
üblichen Windows-DAUs, die jeden unpassenden Mist wahrscheinlich mit 
Excel machen "Weil ich ja nur das kenne". Und auf der anderen Seite sind 
vor allem in der Industrie die Manager, denen dann vom MCS*-Berater die 
tollen neuen Sachen vorgestellt werden. Wie bekannt ist bei MS ja jede 
neue Version "das beste X, das es je gab"

Torsten C. schrieb:
> Wie geht das? Immer, wenn ich versuchen will, das heraus zu
> finden, steht da: Mach das per "API-Layer", "WEB-Service" oder sonstwas.

Eine Datenbank hat eine API über die du mit ihr kommunizierst. Für die 
meisten Programmiersprachen gibt es schon fertige Funktionen dafür.
Hier ist die komplette Doku von MySQL, wenn es ganz selbst machen 
willst: http://dev.mysql.com/doc/

SQLite ist übrigens auch möglich, musst du ja auch nur ansprechen.

node.js kann auch mit allen üblichen Datenbanken reden.

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.