1

I would like to create around 10,000 clients and use them to send and recieve messages from Flask-Socketio server. I am using the default Flask Werkzeug development web server.

This is the app.py

from flask import Flask, render_template
from flask_socketio import SocketIO

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

@socketio.on('message')
def handle_message(message):
    print(message)

if __name__ == '__main__':
    socketio.run(app,debug=True)

This is the test_client.py

import socketio
from multiprocessing.pool import ThreadPool

# standard Python
sio = socketio.Client()

def f(thread):
    server = 'http://127.0.0.1:5000/' + str(thread)
    s = f'/{thread}'
    sio.connect(server)
    sio.emit('message', {'Hello': i}, namespace=s)

threads = 5
t = ThreadPool(threads)
t.map(f, range(0, threads))

Current test_client.py's Terminal Output:

raise exceptions.BadNamespaceError(
socketio.exceptions.BadNamespaceError: /2 is not a connected namespace.

Expected app.py's Terminal Output:

Hello: 0
Hello: 1
Hello: 2
Hello: 3
Hello: 4

Please if there is a different/ better way of doing this, send me the doc link to check.

1 Answers1

1

There are a couple of problems with your design.

In the client, you are using five different namespaces to connect to the server, /0 to /4. But in the server you have not defined any of these, your server operates under the default namespace /. So all these client connections are going to fail, because the server does not accept connections on unknown namespaces. For a namespace to be known, you have to implement at least one handler for it.

But it is impractical to have to define handlers for that many namespaces, though. Namespaces are not a good feature to use in this case, because they cannot be added dynamically.

So the first change is to have your clients connect using the default namespace.

The second problem is that you are using a single client instance in all your threads. This is not how the client works, a client instance can only hold one connection. The solution is to create a client instance inside each thread.

The changes for the above two problems are all in the client. Here is how I changed your client to work:

import socketio
from multiprocessing.pool import ThreadPool

def f(thread):
    sio = socketio.Client()
    server = 'http://127.0.0.1:5000'
    sio.connect(server)
    sio.emit('message', {'Hello': thread})

threads = 5
t = ThreadPool(threads)
t.map(f, range(0, threads))

Output in the server:

{'Hello': 3}
{'Hello': 0}
{'Hello': 1}
{'Hello': 2}
{'Hello': 4}
Miguel Grinberg
  • 65,299
  • 14
  • 133
  • 152
  • This worked. However, I am facing yet another issue where the terminal in the app.py says when I put threads = 500: ``` Python38\site-packages\eventlet\hubs\selects.py", line 42, in wait r, w, er = select.select(reader_fds, writer_fds, all_fds, seconds) ValueError: too many file descriptors in select() ``` –  Nov 24 '22 at 12:20
  • Why are you using eventlet? This is an asynchronous framework, using it with threads makes no sense. – Miguel Grinberg Nov 27 '22 at 15:02
  • I see, Honestly, i didn't know it was using eventlet. i just noticed now. May I know what should I be using instead? –  Nov 27 '22 at 15:35
  • I really don't know, that is up to you to decide? I mean, you decided to install eventlet, right? Why did you do it? If you have a valid reason, then you should understand how to work with greenlets, which are the equivalent to threads when you work with eventlet or gevent. – Miguel Grinberg Nov 27 '22 at 17:19
  • I see, to be honest, I am not sure what to use. I just want something that can support at least 10,000 users. so I wanted a way to test that. The method of testing is what I really can't find anywhere. I saw a Repo called Thor. but it requires a ws:// link and Flask-Socketio only gives me HTTP and not sure how to change that. so I was trying threading to test. –  Nov 28 '22 at 11:33
  • Hi, after some research, I found Thor doesn't work with SocketIO. So I tried Artillery and it is able to do the test. I just noticed that you sir are the author of Flask-SocketIO so I wanted to ask After a room becomes empty, will it close automatically? or will it be heavy on the memory? –  Nov 28 '22 at 15:39
  • 1
    Rooms are deleted automatically when they empty. – Miguel Grinberg Nov 28 '22 at 16:41