我正在尝试一步步构建一个websocket服务器。但是当我尝试使用 eventlet 或 gevent 时遇到了关键问题。
[uwsgi]
chdir = /home/user/websocket
module=websocket:app
callable=app
processes=4
socket=/home/user/websocket/uwsgi.sock
uid = user
gid = user
chmod-socket=664
http-socket = :15000
log-reopen=true
die-on-term=true
master=true
vacuum=true
plugin=python3
virtualenv = /home/user/websocket/web
gevent = 100
from flask import Flask
from flask_socketio import SocketIO, send, emit
app = Flask(__name__)
socketio = SocketIO(app, logger=True, engineio_logger=True, cors_allowed_origins='*')
@socketio.on('connect')
def connected():
print('-'*30, '[connect]', '-'*30)
@socketio.on('message')
def handle_message(data):
print('-'*30, '[message]', '-'*30)
print('received message: ' + data)
send(data) # Echoes back the received message
@socketio.on_error() # This decorator handles all errors including connect_error
def handle_error(e):
if isinstance(e, Exception):
print('An error occurred:', str(e))
# Here, you can log the error or perform any necessary action.
# For example, you can check if it's a connect_error and take appropriate action.
@app.route("/")
def hello():
return "Connected"
if __name__ == '__main__':
socketio.run(app)
我跑了:
uwsgi --ini uwsgi.ini
但我收到错误:
Traceback (most recent call last):
File "/home/user/websocket/web/lib/python3.10/site-packages/flask/app.py", line 1478, in __call__
return self.wsgi_app(environ, start_response)
File "/home/user/websocket/web/lib/python3.10/site-packages/flask_socketio/__init__.py", line 43, in __call__
return super(_SocketIOMiddleware, self).__call__(environ,
File "/home/user/websocket/web/lib/python3.10/site-packages/engineio/middleware.py", line 63, in __call__
return self.engineio_app.handle_request(environ, start_response)
File "/home/user/websocket/web/lib/python3.10/site-packages/socketio/server.py", line 428, in handle_request
return self.eio.handle_request(environ, start_response)
File "/home/user/websocket/web/lib/python3.10/site-packages/engineio/server.py", line 271, in handle_request
packets = socket.handle_get_request(
File "/home/user/websocket/web/lib/python3.10/site-packages/engineio/socket.py", line 90, in handle_get_request
return getattr(self, '_upgrade_' + transport)(environ,
File "/home/user/websocket/web/lib/python3.10/site-packages/engineio/socket.py", line 146, in _upgrade_websocket
ws(environ, start_response)
File "/home/user/websocket/web/lib/python3.10/site-packages/engineio/async_drivers/eventlet.py", line 40, in __call__
raise RuntimeError('You need to use the eventlet server. '
RuntimeError: You need to use the eventlet server. See the Deployment section of the documentation for more information.
所以我尝试将“http-websockets = true”放入ini文件中,但得到了相同的错误。
<!DOCTYPE html>
<html>
<head>
<title>Flask SocketIO Client</title>
<script src="https://cdn.socket.io/4.0.0/socket.io.min.js"></script>
</head>
<body>
<input type="text" id="messageInput" placeholder="Type a message...">
<button onclick="sendMessage()">Send</button>
<div id="messages"></div>
<script>
var socket = io('http://localhost:15000'); // Change to your server's address and port
socket.on('connect', function() {
console.log('Connected to the server.');
});
socket.on('message', function(data) {
console.log('Received message:', data);
document.getElementById('messages').innerText += data + '\n';
});
function sendMessage() {
var message = document.getElementById('messageInput').value;
console.log('sending...:', message);
socket.emit('message', message);
document.getElementById('messageInput').value = '';
}
</script>
</body>
</html>
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run(port=5001) # Run on a different port than your SocketIO server
在客户端页面,显示此错误:
POST http://localhost:15000/socket.io/?EIO=4&transport=polling&t=Ondmm8T&sid=BooMMCC89x9oei5_AAAQ 400 (BAD REQUEST)
websocket.js:88 WebSocket connection to 'ws://localhost:15000/socket.io/?EIO=4&transport=websocket&sid=1_GSTZsrzqFdezzbAAAP' failed:
请帮我解决这个问题。
听起来您安装了多个受支持的库,因此 Socket.IO 需要知道您要使用其中哪个。默认的是 eventlet,但您使用的是 uWSGI,因此您必须通过将
async_mode='gevent_uwsgi'
添加到您的 SocketIO()
构造函数来明确告诉它使用 uWSGI 逻辑。
我还建议您查看文档以了解如何配置uWSGI。您这样做的方式不支持多个工作进程,您应该运行一个工作进程,它可以通过 gevent 处理数百/数千个并发客户端。