【发布时间】:2019-11-20 19:50:25
【问题描述】:
我正在使用 macOS Mojave 和 Python 3.7。在我的工作中,我想从信号处理程序中完全关闭 flask-socketio 服务器,在我的代码中定义为 SignalHandler。我注意到,如果没有信号处理程序,可以使用 Ctrl-C 完全关闭服务器。但是,信号处理程序对我的工作来说是必需的。我在网上搜索并找不到在我的情况下关闭服务器的解决方案。供您参考,我找到了通过“call flask-socketio stop from HTTP or SocketIO handler function”或“shut down a gevent (pywsgi) server gracefully”关闭服务器的解决方案。
示例代码如下:
import os
import threading
import signal
import requests
from flask import Flask, send_from_directory
from flask_socketio import SocketIO, Namespace
import eventlet
class WebsiteCreator(threading.Thread):
def __init__(self):
super().__init__()
def run(self):
app = Flask(__name__, template_folder="templates",
static_folder="templates/static")
app.config['SECRET_KEY'] = 'Secret!'
socketio = SocketIO(app, engineio_logger=True, logger=True)
# Create a URL route in our application for "/"
@app.route('/')
def test_page():
"""
This function loads the homepage
"""
return send_from_directory(
os.path.join(app.root_path, 'templates'),
"index1.html"
)
@app.route('/stop', methods=['POST'])
def shutdown_server():
"""
This function stops the flask-socketio server
"""
print("Received request to shut down the server.")
socketio.stop() #something wrong here, but don't know how to solve
return "The server has been shut down."
class MyCustomNamespace(Namespace):
def on_connect(self):
print("Client just connected")
def on_disconnect(self):
print("Client just left")
def on_messages(self, data):
print(f"\nReceived data from client: \n {data}\n")
return data
socketio.on_namespace(MyCustomNamespace('/channel_A'))
try:
eventlet.wsgi.server(
eventlet.wrap_ssl(eventlet.listen(("localhost", 8080)),
certfile='server.crt',
keyfile='server.key',
server_side=True), app)
except Exception as e:
print(f"Website is not established due to:\n{e}")
# Terminate code from shell
class SignalHandler(object):
def __init__(self):
pass
def __call__(self, signum, frame):
print("Shutting down the website.")
# Begin 'something' here to shut down the server...
shutdown_server = requests.post("https://localhost:8080/stop", data=None)
print(f"Shut down the server feedback: {shutdown_server}")
# 'Something' ends here
print("The website has been shut down.")
if __name__ == '__main__':
WebsiteCreator().start()
# If the following part is not included, the server can be shut down using Ctrl-C
handler = SignalHandler()
signal.signal(signal.SIGINT, handler)
在代码中,我在一个线程中运行 flask-socketio 服务器。我想通过在 SignalHandler 中执行一些操作来关闭服务器。
然而,当我使用 Ctrl-C 退出系统时,出现了一些异常:
^C
Shutting down the website.
(23066) accepted ('127.0.0.1', 49720)
Received request to shut down the server.
127.0.0.1 - - [22/Nov/2019 13:08:18] "POST /stop HTTP/1.1" 200 0 0.000365
wsgi exiting
Exception ignored in: <module 'threading' from '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py'>
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py", line 1308, in _shutdown
lock.acquire()
File "web_app.py", line 74, in __call__
shutdown_server = requests.post("https://localhost:8080/stop", data=None)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/requests/api.py", line 116, in post
return request('post', url, data=data, json=json, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/requests/api.py", line 60, in request
return session.request(method=method, url=url, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/requests/sessions.py", line 533, in request
resp = self.send(prep, **send_kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/requests/sessions.py", line 646, in send
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/hubs/kqueue.py", line 105, in wait
readers.get(fileno, hub.noop).cb(fileno)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/greenthread.py", line 221, in main
result = function(*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/wsgi.py", line 818, in process_request
proto.__init__(conn_state, self)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/wsgi.py", line 357, in __init__
self.handle()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/wsgi.py", line 390, in handle
self.handle_one_request()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/wsgi.py", line 419, in handle_one_request
self.raw_requestline = self._read_request_line()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/wsgi.py", line 402, in _read_request_line
return self.rfile.readline(self.server.url_length_limit)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/socket.py", line 589, in readinto
return self._sock.recv_into(b)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/green/ssl.py", line 241, in recv_into
return self._base_recv(nbytes, flags, into=True, buffer_=buffer)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/green/ssl.py", line 256, in _base_recv
read = self.read(nbytes, buffer_)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/green/ssl.py", line 176, in read
super(GreenSSLSocket, self).read, *args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/eventlet/green/ssl.py", line 150, in _call_trampolining
return func(*a, **kw)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ssl.py", line 926, in read
raise ValueError("Read on closed or unwrapped SSL socket.")
r = adapter.send(request, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/requests/adapters.py", line 498, in send
ValueError: Read on closed or unwrapped SSL socket.
Removing descriptor: 8
142f38bdaaf34c7e8883e99a766fe310: Unexpected error "Read on closed or unwrapped SSL socket.", closing connection
raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))
请给我一些想法!提前致谢。
【问题讨论】:
-
Flask-SocketIO 服务器包含一个stop() 方法,您可以使用它来通知服务器关闭。您的情况的复杂性是需要从处理程序调用此方法。您可以做的是从您的信号处理程序向服务器发送请求,等待请求返回,然后退出处理程序并让应用程序继续让服务器正常结束。
-
@Miguel 感谢您的回复!我会试试的。
-
@Miguel 嗨,我尝试发送请求以停止服务器。但提出了一些例外情况。您可以查看更新后的问题以获取信息。是不是因为代码没有等待请求返回?我该如何解决这个问题?
-
这些错误是典型的终止服务器进程,我不确定是否存在实际问题。每当我关闭我的 gevent 服务时,我都会收到一系列中止连接的错误,如果你不想看到它们,我只会捕获并忽略它们。
-
我没见过这个错误,但很可能与没有等到服务器完全关闭才退出进程有关。
标签: server python-3.7 shutdown flask-socketio