python - 在 Windows 上的同一端口上运行 Python Web 服务器两次:没有“端口已在使用”消息
问题描述
我在 Windows 7 上。当我启动一个 Bottle 网络服务器时:
run('0.0.0.0', port=80)
然后再次运行相同的 Python 脚本,它不会因错误而失败 Port already in use
(这应该是正常行为),而是再次成功启动 Python 脚本!
问题:如何以简单的方式阻止这种行为?
这与侦听同一端口的多个进程有关吗?,但是如何在 Python 上下文中防止这种情况发生呢?
解决方案
这是 Windows 特定的行为,需要SO_EXCLUSIVEADDRUSE
在绑定网络套接字之前使用该选项。
来自 Windows Socket 2 文档中的使用 SO_REUSEADDR 和 SO_EXCLUSIVEADDRUSE文章:
在引入 SO_EXCLUSIVEADDRUSE 套接字选项之前,网络应用程序开发人员几乎无法阻止恶意程序绑定到网络应用程序绑定了自己的套接字的端口。为了解决这个安全问题,Windows 套接字引入了 SO_EXCLUSIVEADDRUSE 套接字选项,该选项在带有 Service Pack 4 (SP4) 及更高版本的 Windows NT 4.0 上可用。
...
SO_EXCLUSIVEADDRUSE 选项是通过调用 setsockopt 函数来设置的,其中 optname 参数设置为 SO_EXCLUSIVEADDRUSE 并且 optval 参数设置为布尔值 TRUE,然后再绑定套接字。
为了使用 Bottle 模块执行此操作,您必须创建一个自定义后端,以便在绑定之前访问套接字。这提供了一个机会来设置所需的套接字选项,如文档所述。
Bottle Deployment 文档中对此进行了简要描述:
如果您最喜欢的服务器没有适配器,或者您需要对服务器设置进行更多控制,您可能需要手动启动服务器。
下面是一个修改版的Bottle Hello World 示例,它演示了这一点:
import socket
from wsgiref.simple_server import WSGIServer
from bottle import route, run, template
@route('/hello/<name>')
def index(name):
return template('<b>Hello {{name}}</b>!', name=name)
class CustomSocketServer(WSGIServer):
def server_bind(self):
# This tests if the socket option exists (i.e. only on Windows), then
# sets it.
if hasattr(socket, 'SO_EXCLUSIVEADDRUSE'):
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1)
# Everything below this point is a concatenation of the server_bind
# implementations pulled from each class in the class hierarchy.
# wsgiref.WSGIServer -> http.HTTPServer -> socketserver.TCPServer
elif self.allow_reuse_address:
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind(self.server_address)
self.server_address = self.socket.getsockname()
host, port = self.server_address[:2]
self.server_name = socket.getfqdn(host)
self.server_port = port
self.setup_environ()
print "Serving..."
run(host='localhost', port=8080, server_class=CustomSocketServer)
请注意,需要复制的代码来维持超类的预期行为。
所有的超类实现都是server_bind()
从调用它们的父类开始的server_bind()
。这意味着调用它们中的任何一个都会导致立即绑定套接字,从而消除设置所需套接字选项的机会。
我使用 Python 2.7 在 Windows 10 上对此进行了测试。
第一个例子:
PS C:\Users\chuckx\bottle-test> C:\Python27\python.exe test.py
Serving...
第二审:
PS C:\Users\chuckx\bottle-test> C:\Python27\python.exe test.py
Traceback (most recent call last):
File "test.py", line 32, in <module>
server_class=CustomSocketServer)
File "C:\Python27\lib\wsgiref\simple_server.py", line 151, in make_server
server = server_class((host, port), handler_class)
File "C:\Python27\lib\SocketServer.py", line 417, in __init__
self.server_bind()
File "test.py", line 19, in server_bind
self.socket.bind(self.server_address)
File "C:\Python27\lib\socket.py", line 228, in meth
return getattr(self._sock,name)(*args)
socket.error: [Errno 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted
推荐阅读
- php - 使用 pecl 在 Mac 上安装 Redis 后无法正常工作
- docker - 使用 keycloak 作为 gitlab-ci 服务
- makefile - 如何仅在列表中的目标上使用 makefile 中的 .NOTPARALLEL?
- svg - svg - 如何绘制椭圆渐变?
- python - 如何在 Python 中将列中的字符串格式更改为 3 位数字“000”
- python - 有没有办法只从 PNG 中提取“角”顶点?
- scala - 使用 scala slick 从 .csv 文件填充 H2 in-mem db
- reactjs - 开玩笑的快照返回属性而不是 htmlFor
- mysql - Hangfire - Asp.Net Core 3.1 - 错误日志应用程序启动异常
- javascript - 跟踪两个函数是否已执行