Python - Detect browser closure to kill webserver

Ok, I'm writing a pyqt software to generate a webpage. Due to some security issues with Chrome and other things, I need a webserver to test the webpage.

So I thought to create a button called run, that you can click or press f5 to start a server, and open the browser to the page. The snippet of code that this button calls, simplified (there is some code to do things, including changing current directory and such), looks like this:

import sys 
import webbrowser
from SimpleHTTPServer import SimpleHTTPRequestHandler as HandlerClass
from BaseHTTPServer import HTTPServer as ServerClass

Protocol = 'HTTP/1.0'
port = 8080
ip = '127.0.0.1'

new = 2 #goes to new tab
url = "http://"+ip+":{0}".format(port)

serverAddress = (ip,port)
HandlerClass.protocol = Protocol
httpd = ServerClass(serverAddress, HandlerClass)

sa = httpd.socket.getsockname()
webbrowser.open(url,new=new)
httpd.serve_forever()

Ok, the problem is as serve_forever is called, it can be expected to serve forever. Is there a way to kill the server after browser is closed?

Edit: I understand many people recommend using threads but I can't find a way to detect that the browser has closed or killing the thread in system monitor (I'm on Ubuntu) while testing.

Edit2: ok, I've read webbrowser.py, it doesn't seem to return any sort of process identifier...

Edit3: I'm reflecting on this, maybe the correct approach would be checking if someone is accessing the server, and if not, then kill it... This way I can detect if the tab was closed... Problem is the only way I can think uses a dummy page with this power that loads whatever page to test inside, which seems too hackish...

It seems if I can find a way of doing this, maybe through error responses...I can do a webserver in a subprocess that has a while and exits by itself like the one here:

import sys 
#from threading import Thread
import webbrowser
import BaseHTTPServer 
import SimpleHTTPServer

serverClass=BaseHTTPServer.HTTPServer
handlerClass=SimpleHTTPServer.SimpleHTTPRequestHandler

Protocol = "HTTP/1.0"
port = 8080
ip = '127.0.0.1'

new = 2 #2 goes to new tab, 0 same and 1 window.
url = "http://"+ip+":{0}".format(port)

handlerClass.protocol = Protocol
httpd = serverClass((ip,port), handlerClass)

sa = httpd.socket.getsockname()
print("\n---\nServing HTTP on {0}, port {1}\n---\n".format(sa[0],sa[1]) )
browserOk = webbrowser.open(url,new=new)

def runWhileTrue():
    while True:
        #print(vars(httpd))
        httpd.handle_request()

runWhileTrue()

Right now I'm thinking about using a timer like a watchdog, if the server is not used more then a period, it get's killed... But I think this is an awful solution... I wanted the browser to ping for it for some time while the tab is opened...maybe, don't know if optimal, looking this code right now : SimpleHTTPServer and SocketServer .

Thinking maybe if the server could understand a message from the website it could break loop. The tab closure could be detected in javascript like here : Browser/tab close detection using javascript (or any other language). Don't know how to communicate this to the server.

EditFinal:

In the javascript code of the webpage, I've inserted:

window.addEventListener('unload', function (e) { e.preventDefault(); jsonLevelGet("http://127.0.0.1:8081/exit.json");  }, false);

Then, the python code is this server.py:

import sys 
from threading import Thread
import webbrowser
import BaseHTTPServer 
import SimpleHTTPServer

serverClass=BaseHTTPServer.HTTPServer
handlerClass=SimpleHTTPServer.SimpleHTTPRequestHandler

Protocol = "HTTP/1.0"
port = 8080
ip = '127.0.0.1'
admIp = ip
admPort = 8081

new = 2 #2 goes to new tab, 0 same and 1 window.
url = "http://"+ip+":{0}".format(port)

handlerClass.protocol = Protocol
httpdGame = serverClass((ip,port), handlerClass)
httpdAdm = serverClass((admIp,admPort), handlerClass) 

sa = httpdGame.socket.getsockname()
sb = httpdAdm.socket.getsockname()
print("\n---\nServing HTTP on {0}, port {1}\n---\n".format(sa[0],sa[1]) )
print("\n---\nAdm HTTP listening on {0}, port {1}\n---\n".format(sb[0],sb[1]) )
browserOk = webbrowser.open(url,new=new)

def runGameServer():
    httpdGame.serve_forever()
    print("\nrunGameServer stopped\n")
    httpdAdm.shutdown()
    return

def runAdmServer():
    httpdAdm.handle_request()
    httpdGame.shutdown()
    print("\nrunAdmServer stopped\n")
    return

gameServerThread = Thread(target=runGameServer)
gameServerThread.daemon = True
admServerThread = Thread(target=runAdmServer)

gameServerThread.start()
admServerThread.start()
admServerThread.join()

It works! When the tab is closed, the server.py code exits! Thanks @st.never!


ANSWERS:


As you said, you could detect (in Javascript, in the browser) that the window is being closed, and send one last request to the server to shut it down.

If you don't want to inspect all the requests searching for the "poweroff request", you can instead have your server listen on two different ports (probably on different threads). For example, the "main" server listens on port 8080 with the current behaviour, and a separate instance listens on port 8081. Then you can simply shut down the server whenever any request reaches port 8081.



 MORE:


 ? Inducing a function after session is destroyed
 ? Is there any way to call a function periodically in JavaScript?
 ? Perform action when browser tab is closed (Javascript)
 ? How to detect a close of a browser using javascript or jquery
 ? Detecting JavaScript popup window close event in browser
 ? Browser Tab Close Event for javascript or ExtJS
 ? How to delete a localStorage item when the browser window/tab is closed?
 ? How to delete a localStorage item when the browser window/tab is closed?
 ? How to delete a localStorage item when the browser window/tab is closed?
 ? Remove/Clear local storage when all tabs are closed