raksh93
raksh93

Reputation: 67

PyQt SimpleHTTPServer: GUI freezes on starting server

I am trying to create a simple desktop app using PyQt that runs a SimpleHTTPServer on clicking a start server button. I have tried using threads(both python threads and Qthread) and understand that this is not possible as it runs into issues with the GIL. Here's the code

def btn_startserver_clicked(self):
    server_thread=threading.Thread(target=start_server())
    server_thread.start()


def start_server():
    #to get server's IP
    host=([(s.connect(('8.8.8.8', 80)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1])
    start=8000
    end=56999
    PORT = random.randint(start,end)
    print host,":",PORT
    httpd=ThreadedServer(("",PORT), SimpleHTTPServer.SimpleHTTPRequestHandler)
    httpd.handle_request()`

I tried creating another process but the same thing happened. Also, if I create another process a new window pops up each time a request is served.

def btn_startserver_clicked(self):
    if __name__=='__main__':
        server_process=Process(target=start_server())
        server_process.start()

Is there any way around this? I feel using multiprocessing is the right approach but I am new to this and can't figure out why it still freezes.

Thanks

Upvotes: 5

Views: 3371

Answers (2)

three_pineapples
three_pineapples

Reputation: 11869

The issue with your examples that lock the GUI is that rather than passing a reference to the function when creating the thread, you are actually running the function immediately and the thread is never created. For example, you should be doing:

server_thread=threading.Thread(target=start_server)

Note that I drop the brackets on start_server otherwise the code waits for start_server() to finish executing before creating the threading.Thread object, and uses the return value from start_server() as the value for the target attribute.

A final suggestion, you should really store the created thread as self.server_thread to prevent it from being garbage collected.

Upvotes: 2

ekhumoro
ekhumoro

Reputation: 120678

Not exactly sure what you're trying to do, but this might help you get started:

import sys
from urllib.request import urlopen
from http.server import HTTPServer, SimpleHTTPRequestHandler
from PyQt4 import QtCore, QtGui

HOST, PORT = '127.0.0.1', 12345

class HttpDaemon(QtCore.QThread):
    def run(self):
        self._server = HTTPServer((HOST, PORT), SimpleHTTPRequestHandler)
        self._server.serve_forever()

    def stop(self):
        self._server.shutdown()
        self._server.socket.close()
        self.wait()

class Window(QtGui.QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.button = QtGui.QPushButton('Start', self)
        self.button.clicked.connect(self.handleButton)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.button)
        self.httpd = HttpDaemon(self)

    def handleButton(self):
        if self.button.text() == 'Start':
            self.httpd.start()
            self.button.setText('Test')
        else:
            urlopen('http://%s:%s/index.html' % (HOST, PORT))

    def closeEvent(self, event):
        self.httpd.stop()

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())

Upvotes: 4

Related Questions