以编程方式关闭烧瓶套接字 io 服务器

Posted

技术标签:

【中文标题】以编程方式关闭烧瓶套接字 io 服务器【英文标题】:Closing flask-socket io server programmatically 【发布时间】:2021-06-10 14:12:23 【问题描述】:

我是服务器开发的新手,所以请善待... 我正在开发一个启动 flask-socketio 服务器的测试应用程序,在与客户端交互后,它需要关闭并打开另一个实例。 然而这是不可能的 我得到错误

File "C:\Python39\lib\site-packages\eventlet\convenience.py", line 78, in listen
sock.bind(addr)
OSError: [WinError 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted

如何以编程方式关闭服务器? 我在这里查看了How to stop flask application without using ctrl-c 的答案,并且使用一个过程确实可以解决问题。 但是我真的不想有一个单独的进程,因为在进程之间共享变量太棘手了。

我也从同一篇文章中不明白如何从服务器向服务器本身发送请求以关闭烧瓶应用程序。 这是我的代码示例

import socketio
import eventlet
import eventlet.wsgi
from flask import Flask, render_template
import socket
import threading
import time


ip_addr=socket.gethostbyname(socket.gethostname())
appFlask = Flask(__name__)
sio = socketio.Server( )  #engineio_logger=True,logger=True)
# wrap Flask application with engineio's middleware
app = socketio.Middleware(sio, appFlask)

@sio.on('connect')
def connect(sid, environ):
    print('connect ', sid)

@sio.on('message')
def message(sid, data):
    print('message '+data, data)

@sio.on('disconnect')
def disconnect(sid):
    print('disconnect ', sid)

@sio.on('result')
def result(sid,data):
    print('result ', sid)

def worker1():
    socket_port=3000
    eventlet.wsgi.server(eventlet.listen((ip_addr, socket_port)), app)


if __name__ == '__main__':

    sio.start_background_task(worker1)
    #   do some stuff and interact with the client
    sio.sleep(2)
    # how can I close  the server so that I can do the following?
    sio.start_background_task(worker1)

编辑了烧瓶套接字 io 功能

import socketio
import eventlet
import eventlet.wsgi
from flask import Flask, render_template
import socket
import threading
import time
import requests
from flask import request
from flask_socketio import SocketIO

ip_addr=socket.gethostbyname(socket.gethostname())
socket_port=3000

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
sio = SocketIO(app)

@app.route('/stop')
def stop():
    sio.stop()

@sio.on('connect')
def connect(sid, environ):
    print('connect ', sid)

@sio.on('message')
def message(sid, data):
    print('message '+data, data)

@sio.on('disconnect')
def disconnect(sid):
    print('disconnect ', sid)

@sio.on('result')
def result(sid,data):
    print('result ', sid)


def worker1():
    eventlet.wsgi.server(eventlet.listen((ip_addr, socket_port)), app)



if __name__ == '__main__':

    eventlet_thr=sio.start_background_task(worker1)
    #   do some stuff and interact with the client
    sio.sleep(2)
    # now wait  that the server is stopped

    # invoke in a different process a request to stop

    eventlet_thr.join()


    # how can I close  the server so that I can do the following?
    sio.start_background_task(worker1)

【问题讨论】:

【参考方案1】:

你好像在使用eventlet web server,所以问题是如何停止eventlet web server,Flask-SocketIO与服务器无关。

为方便起见,Flask-SocketIO 提供了stop() 方法,您必须从处理程序内部调用该方法。我不确定当服务器在不是主线程的线程上运行时这是否有效,但您必须对其进行测试。

所以基本上你需要做的是添加一个强制服务器退出的端点,可能是这样的:

@app.route('/stop')
def stop():
    sio.stop()
    return ''

那么你可以按如下方式启动和停止服务器:

if __name__ == '__main__':
    thread = sio.start_background_task(worker1)
    #   do some stuff and interact with the client
    requests.get('http://localhost:5000/stop')
    thread.join()

【讨论】:

感谢您对 eventlet 服务器的建议和澄清。我尝试了上面的 sn-p 但请求似乎从未到达停止处理程序。脚本只是永远挂在请求行中。 确保 URL 正确。另请注意,我忘记在我现在添加的停止处理程序上添加响应。 谢谢 Miguel,我仔细检查了 URL 是否正确。经过一些调试后,我发布了它以调用 sio.stop 我需要使用烧瓶套接字 io 实现(请参阅上面的编辑代码)。其次,我需要从不同的进程发送请求,所以我创建了一个新的 python 文件,用于发送请求。最后,我看到请求被接收和处理,如果 eventlet 引发 SystemExit 异常,导致整个 python 运行退出,因此我无法通过重新打开新服务器实例继续执行脚本 我在回复中提到,当服务器在辅助线程中运行时,我不确定这是否可行。 是的,我知道这一点,这就是为什么我试图从另一个 python 执行发送请求。这确实有效,但 sio.stop() 引发的断言导致主线程退出,所以我之后无法打开新的服务器实例。不过还是谢谢!

以上是关于以编程方式关闭烧瓶套接字 io 服务器的主要内容,如果未能解决你的问题,请参考以下文章