在Python中关闭/重启socket

2 投票
5 回答
9032 浏览
提问于 2025-04-16 12:00

我准备做一个简单的测试,想用PagSeguro(巴西的“PayPal”),为此我下载了他们的Python服务器来在我的本地电脑上测试。我用的是Mac,正在运行XAMPP服务器(Apache和MySQL部分在我的操作过程中是开启的)。

我的问题对懂Python和套接字的人来说应该很简单,但由于我自己在这方面的知识有限,没能把事情搞明白。

简单来说,我想知道:如何在终端中释放一个套接字,这个套接字的程序在关闭之前没有正常关闭。还有,如何写一个Python函数,让我在想关闭套接字和停止/重启服务器的时候调用。

场景是这样的:我在终端启动服务器(用命令:# sudo python ./PagSeguroServer.py),一切正常,我做了一些想做的测试。然后,我需要更改一些服务器的设置,为了让它生效,我需要重启服务器。我是通过关闭终端窗口来解决的,但当我重新打开终端并输入同样的命令来再次启动服务器时,出现了“socket.error: [Errno 48] Address already in use”的错误。好吧,我明白为什么会这样,但不知道怎么解决,于是我在网上搜索,发现有个建议是要在代码中添加

socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

。我查看了Python类,尽量把它放进去(如下所示),但问题没有解决。由于我的“搜索和拼凑”似乎没有帮助,我决定放弃,发这个定制的问题!

这是服务器代码的一部分:

class SecureHTTPServer(HTTPServer):
    '''Servidor HTTPS com OpenSSL.'''
    def __init__(self, server_address, HandlerClass,fpem):
        BaseServer.__init__(self, server_address, HandlerClass)
        ctx = SSL.Context(SSL.SSLv23_METHOD)
        ctx.use_privatekey_file (fpem)
        ctx.use_certificate_file(fpem)
        self.socket = SSL.Connection(ctx, socket.socket(self.address_family,
                                                        self.socket_type))
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.server_bind()
        self.server_activate()

    ....

def run(HandlerClass = HTTPSHandler, ServerClass = SecureHTTPServer):
    '''Roda o servidor'''
    server_address = ('', 443) # (address, port)
    httpd = ServerClass(server_address, HandlerClass, fpem)
    httpd.serve_forever()

if __name__ == '__main__':
    run()

注意:有一次我确实成功重新打开了它,那是在我添加setsockopt调用之前,我感觉套接字在超时后关闭了——我在某处读到过这个。不过,这次似乎不再发生了——我等了好几次也试过。

编辑:最后我解决了这个问题:需要杀掉占用套接字的Python进程(见jd的回答中的评论),然后添加了KeyboardInterrupt捕获,以便能够正确关闭套接字。谢谢大家!

5 个回答

1

在终端窗口中使用以下命令来关闭TCP端口28355:

npx kill-port 28355

在我的Python套接字服务器脚本中,我使用了以下几行代码:

import os
os.system("npx kill-port 28355")

这个命令可以解决“地址已在使用中”的错误。
在我找到的所有解决方案中,这个是唯一能解决这个错误的方法,比如启用SO_REUSEADDR选项并没有用。

1

你可以写一个函数来正确地关闭套接字(socket),并使用 atexit.register() 来注册这个函数,让它在程序结束时自动运行。想了解更多,可以查看这个链接:http://docs.python.org/library/atexit.html

1

如果你是通过按 Ctrl+C 来关闭程序的话,可以试着在你的代码里捕捉一个叫做 KeyboardInterrupt 的异常(更好的方法是处理 SIGINT 信号),这样在退出之前就可以优雅地关闭连接。

当然,这样做并不能阻止你用其他方式强行结束程序,从而导致连接不再有效,但你也可以尝试处理这些情况。

撰写回答