TCP Request per Webserver triggern

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Tele
User
Beiträge: 5
Registriert: Montag 31. August 2015, 13:06

Hallo zusammen!

Ich bin sehr neu in Python und habe ein Problem bei folgendem Vorhaben:
Ich möchte einen Webserver laufen lassen (BaseHTTPServer) um damit eine Website zu hosten.
Parallel dazu soll ein TCP-Server laufen, welcher Verbindungsanfragen von einem Client erhält.
Sobald auf der Website ein Button getriggert wurde, möchte ich dem TCP-Client eine Nachricht senden.

Im Moment fange ich ich die Get-Requests des Webservers ab um die Parameter in der URL zu parsen, die mir der HTML-Button generiert (jeder Button
soll etwas anderes triggern). Dort ist es mir aber nicht möglich auf meinen TCP-Server zuzugreifen.
Ich verstehe noch nicht wirklich das Konzept mit den Handler-Klassen :K
Ich hoffe, dass war einigermaßen verständlich erklärt :lol:

LG,

Der Tele
Benutzeravatar
sparrow
User
Beiträge: 4187
Registriert: Freitag 17. April 2009, 10:28

Dein bisheriger Code wäre gut.
Tele
User
Beiträge: 5
Registriert: Montag 31. August 2015, 13:06

Alles klar:

Code: Alles auswählen

import cgi
import SocketServer
import threading
from os import curdir, sep
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer


func_request = None
var_backendHandler = None

class BackendHandler(SocketServer.BaseRequestHandler):
    
    def sendRequest(self, message):
        self.request.sendall(message)

    def handle(self):
        print "New connection from {}".format(self.client_address[0])
        while True:
            d = self.request.recv(2000)
            global func_request
            func_request = self.sendRequest
            global var_backendHandler
            var_backendHandler = self
            if not d:
                break
            print(d)


class ServerHandler(BaseHTTPRequestHandler):

    def do_GET(self):
        try:
            if self.path.endswith(".html"):
                f = open(curdir + sep + self.path)

                self.send_response(200)
                self.send_header('Content-type', 'text/html')
                self.end_headers()

                self.wfile.write(f.read())
                f.close()
                return

            if self.path.endswith(".html?btn_login=yes"):

                func_request(var_backendHandler, "Function Call")
                f = open(curdir + sep + "/index.html")

                self.send_response(200)
                self.send_header('Content-type', 'text/html')
                self.end_headers()

                self.wfile.write(f.read())
                f.close()
                return
            return

        except IOError:
            self.send_error(404, 'File not found: %s' % self.path)

    def do_POST(self):
        global rootnode
        try:
            ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))
            if ctype == 'multipart/form-data':
                query = cgi.parse_multipart(self.rfile, pdict)
            self.send_response(301)
            self.end_headers()

            upfilecontent = query.get('upfile')
            print("filecontent", upfilecontent[0])
            self.wfile.write("<HTML>POST OK.<BR><BR>")
            self.wfile.write(upfilecontent[0])
        except:
            pass


def main():
    HOST, PORT = "localhost", 2310
    try:
        tcpServer = SocketServer.TCPServer((HOST, PORT), BackendHandler, bind_and_activate=False)
        tcpServer.allow_reuse_address = True

        webServer = HTTPServer(('', 80), ServerHandler)
        threading.Thread(target=webServer.serve_forever).start()

        tcpServer.server_bind()
        tcpServer.server_activate()
        tcpServer.serve_forever()
    except KeyboardInterrupt:
        print("Keyboard interrupt")
        webServer.socket.close()

if __name__ == '__main__':
    main()
Ich habe versucht die Funktion in einer globalen Variable zu speichern um sie dann aufzurufen, aber das scheint auch nicht zu funktionieren.

LG,
Der Tele
BlackJack

@Tele: Warum kannst Du in einem Handler keine Anfrage an den TCP-Server schicken? Also was hält Dich technisch davon ab?

`BaseHTTPServer` würde ich übrigens höchstens zum Hosten von einer statischen Webseite verwenden. Falls da irgendwas dynamisches passieren soll würde ich eines der Mikrorahmenwerke, beispielsweise Bottle oder Flask, verwenden.

``global`` solltest Du ganz schnell vergessen.

Wenn der HTTP-Server auf das Socket-Server-Objekt zugreifen können soll dann muss man dem das übergeben, also einen eigenen, abgeleiteten Server schreiben. Der HTTP-Anfrage-Handler seinerseits kann auch auf seinen Server, und damit dann auch auf dessen Attribute zugreifen. Auf einen Socket-Server-Request von einem HTTP-Server-Request aus direkt zuzugreifen halte ich für unmöglich weil dazu parallel zum HTTP-Request ja ein Socket-Request existieren muss, und die müssen dann auch noch irgendwie zusammen gehören. Wie stellst Du das denn sicher?

Beschreib doch mal was Du *eigentlich* machen willst.
Tele
User
Beiträge: 5
Registriert: Montag 31. August 2015, 13:06

BlackJack hat geschrieben:@Tele: Warum kannst Du in einem Handler keine Anfrage an den TCP-Server schicken? Also was hält Dich technisch davon ab?
Oh das möchte ich gar nicht. Ich möchte von meinem WebserverHandler eine Methode des TCP-ServerHandler triggern (Wenn ich deine Frage richtig verstanden habe)
BlackJack hat geschrieben: `BaseHTTPServer` würde ich übrigens höchstens zum Hosten von einer statischen Webseite verwenden. Falls da irgendwas dynamisches passieren soll würde ich eines der Mikrorahmenwerke, beispielsweise Bottle oder Flask, verwenden.

``global`` solltest Du ganz schnell vergessen.
Alles klar :D
BlackJack hat geschrieben: Wenn der HTTP-Server auf das Socket-Server-Objekt zugreifen können soll dann muss man dem das übergeben, also einen eigenen, abgeleiteten Server schreiben. Der HTTP-Anfrage-Handler seinerseits kann auch auf seinen Server, und damit dann auch auf dessen Attribute zugreifen. Auf einen Socket-Server-Request von einem HTTP-Server-Request aus direkt zuzugreifen halte ich für unmöglich weil dazu parallel zum HTTP-Request ja ein Socket-Request existieren muss, und die müssen dann auch noch irgendwie zusammen gehören. Wie stellst Du das denn sicher?

Beschreib doch mal was Du *eigentlich* machen willst.
Folgendes:
  • Ich starte mein python Skript
  • Client verbindet sich und wartet auf Antworten
  • User geht auf die Website
  • User klickt button
  • Button triggert eine Nachricht per TCP-Server an den verbundenen Client
BlackJack

@Tele: Dann müsstest Du sowohl einen HTTP-Server als auch einen Socket-Server ableiten, den Socket-Server beim HTTP-Server bekannt machen, damit der dann eine Nachricht an den Socket-Server übergeben kann. Und der Socket-Handler müsste dann bei seinem Server auf so eine Nachricht warten. Eine `Queue.Queue` würde sich da anbieten, weil die schon von Haus aus threadsicher ist. Wobei ich wenn ich mir die `do_GET()`-Methode so anschaue wohl wirklich lieber Bottle oder etwas vergleichbares nehmen würde, statt von Hand auf diesem HTTP-Niveau zu arbeiten und URLs mit einfachen Zeichenkettenfunktionen zu untersuchen und das alles in einer Methode abzuhandeln.

Das nackte ``except:`` ohne eine konkrete Ausnahme in `do_POST()` ist nicht gut. Entweder behandelt man nur die Ausnahmen die man auch erwartet (also mindestens einen `NameError` bei dem Code), oder man protokolliert wenigstens was da so an Ausnahmen ausgelöst wurde. Sonst ist die Fehlersuche ein herumtapsen im dunkeln. An der Stelle sollte man das `logging`-Modul erwähnen. Das hat auch eine Funktion beziehungsweise `Logger` haben eine Methode um Ausnahmen zu protokollieren. Mit Traceback.
Tele
User
Beiträge: 5
Registriert: Montag 31. August 2015, 13:06

Vielen Dank für die Hinweise, da werde ich mich drum kümmern.
Die Frage ist jetzt, wie ich in einer abgeleiteten Klasse von TCPServer einen Request an den Client schicke.
Bis jetzt handele ich die Requests ja in der BackendHandler-Klasse ab (sprich sendRequest(self, message))
Tele
User
Beiträge: 5
Registriert: Montag 31. August 2015, 13:06

Hallo nochmal!

Ich habe viel herumprobiert und bin auf web.py gestoßen und möchte es nun etwas "sauberer" per REST implementieren.
Leider scheitere ich diesmal an globalen Variablen. Ich möchte den REST-Server im Hintergrund laufen lassen.
Wenn eine neue Connection reinkommt, möchte ich diese in einem globalen socket-Objekt speichern um darauf eine Nachricht zu senden,
sollte ein REST Request reinkommen:

Code: Alles auswählen

import web
import SocketServer
import threading

# zu Testzwecken noch drin
class BackendHandler(SocketServer.BaseRequestHandler):
	def handle(self):
		print("New Connection: " + self.client_address[0])
		while True:
			data = self.request.recv(2000)
			if not data:
				break
			self.data += data
		print("Disconnected")


HOST, PORT = "localhost", 2310
server = SocketServer.TCPServer((HOST, PORT), BackendHandler, bind_and_activate=False)
sock = None
urls = (
	'/', 'index',
	'/start', 'start'
)

class index:
	def GET(self):
		return "Hello World!"

class start:
	def GET(self):
		global sock
		print(sock)
		if not sock:
			print("Socket not initialized!")
			return "Error - No connection!"
		sock.send("start")


if __name__ == "__main__":
	restServer = web.application(urls, globals())
	threading.Thread(target=restServer.run).start()

	server.allow_reuse_address = True
        server.server_bind()
        server.server_activate()

        while True:
	        sock = server.get_request()[0]
        	print(sock)
        	msg = sock.recv(2000)
        	if not msg:
                	break
        	print(msg)
Leider bekomme ich immer ein print("Socket not initialized!") :K

Weiß jemand warum die globale Variable ihren Wert verliert/nicht zugewiesen wird?

LG,
Der Tele
Antworten