Python(3.3)Webserver脚本带有一个有趣的错误

时间:2013-06-29 15:54:24

标签: python multithreading http raspberry-pi

我有一个小的python webserver脚本用于托管我自己的网站,完成请求处理和错误返回。这个脚本在我的电脑上完美运行,但是当我在我的覆盆子Pi上尝试它时,它不会每3分钟重启一次(服务器会在15分钟后崩溃,所以每3分钟重启一次似乎很好)。

所以我重写了我的服务器脚本,并检查了第一次启动或重新启动等内容。我只会告诉你代码。

#Handler class above here
...
...
class Server:

    global server_class, server_adress, httpd
    server_class = HTTPServer
    server_adress = ('localhost', 8080)
    httpd = server_class(server_adress, Handler)

    def __init__(self):

        self.status = False
        self.process()

    def process(self):

        print(self.status)

        process = threading.Timer(10, self.process)
        process.start()

        if self.status == True:

            httpd.socket.close()
            self.main()

        if self.status == False:

            self.main()

    def main(self):

        try:

            if self.status == False:

                print("Server online!")
                self.status = True
                httpd.serve_forever()

            if self.status == True:

                print("Server restarted!")
                httpd.serve_forever()

        except KeyboardInterrupt:

            print("Server shutting down...")
            httpd.socket.close()

    if __name__ == "__main__":
        instance = Server()

运行十秒后(它可以运行,我可以在http://localhost:8080/index.html上访问我的网站),它会每十秒钟继续发出以下错误:

File "C:\Users\myname\Dropbox\Python\Webserver\html\server.py", line 187, in main httpd.serve_forever()
File "C:\Python33\lib\socketserver.py", line 237, in serve_forever poll_interval)
File "C:\Python33\lib\socketserver.py", line 155, in _eintr_retry return func(*args)
ValueError: file descriptor cannot be a negative integer (-1)

基本上,我该如何解决这个问题?我可以使用一个带有线程计时器的简单函数来重新启动运行服务器的函数,但不知怎的,这对我的Raspberry Pi不起作用,但它在我的窗口上运行。

编辑: 我还应该注意,第一次启动脚本我可以访问网站,而且速度很快。 10秒后(服务器重启后),我可以访问它,但速度非常慢。再过10秒钟,我无法访问我的网站。

1 个答案:

答案 0 :(得分:1)

您遇到的问题是因为您直接访问服务器的底层套接字。关闭套接字实际上就像拔掉网络连接一样。位于套接字顶部的实际服务器仍然不知道套接字已关闭,并尝试继续提供服务。当套接字关闭时,不再有可用的文件描述符(这是你得到的错误)。

因此,不应该断开服务器的连接,而应该告诉服务器实际上要正常关闭。这允许它完成任何正在进行的连接并安全地释放它可能在后台执行的所有操作。您可以使用shutdown方法执行此操作。执行该操作将在内部告诉服务器记住在下次serve_forever内的循环发生时关闭。

如果我没记错的话,serve_forever是一种阻止方法,这意味着它在执行时不会继续。因此,使服务器重新启动的最简单方法是执行此操作的单个主线程:

while True:
    httpd.serve_forever()

因此,无论何时服务器停止 - 无论出于何种原因 - 它都会立即重新启动。当然,您现在可以添加一些状态变量(而不是True),它允许您实际关闭服务器。例如,在KeyboardInterrupt catch的正文中,您首先将该变量设置为False,然后使用httpd.shutdown()关闭服务器。