├── README.md ├── public ├── index.html └── index.js ├── .gitignore ├── requirements.txt ├── LICENSE ├── async_client.py ├── client.py ├── app.py └── async_app.py /README.md: -------------------------------------------------------------------------------- 1 | Quick Socket.IO Tutorial 2 | ======================== 3 | 4 | This repository contains the code from my video series "Quick Socket.IO 5 | Tutorial". 6 | 7 | Watch it on YouTube: https://www.youtube.com/watch?v=H1eLJMC5oTg&list=PLCuWRxjbgFnPZTBMYbz9UNGvTLNggRMjb 8 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Socket.IO Demo 5 | 6 | 7 |

Socket.IO Demo

8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | var 14 | sdist 15 | develop-eggs 16 | .installed.cfg 17 | lib 18 | lib64 19 | __pycache__ 20 | 21 | # Installer logs 22 | pip-log.txt 23 | 24 | # Unit test / coverage reports 25 | .coverage 26 | .tox 27 | nosetests.xml 28 | 29 | # Translations 30 | *.mo 31 | 32 | # Mr Developer 33 | .mr.developer.cfg 34 | .project 35 | .pydevproject 36 | 37 | docs/_build 38 | venv* 39 | .eggs 40 | .ropeproject 41 | .idea 42 | .vscode 43 | tags 44 | htmlcov 45 | *.swp 46 | 47 | node_modules 48 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp==3.7.3 2 | async-timeout==3.0.1 3 | attrs==20.3.0 4 | bidict==0.21.2 5 | certifi==2020.12.5 6 | chardet==3.0.4 7 | click==7.1.2 8 | dnspython==1.16.0 9 | eventlet==0.30.0 10 | greenlet==0.4.17 11 | gunicorn==20.0.4 12 | h11==0.11.0 13 | httptools==0.1.1 14 | idna==2.10 15 | multidict==5.1.0 16 | python-dotenv==0.15.0 17 | python-engineio==4.0.0 18 | python-socketio==5.0.4 19 | PyYAML==5.3.1 20 | requests==2.25.1 21 | six==1.15.0 22 | typing-extensions==3.7.4.3 23 | urllib3==1.26.2 24 | uvicorn==0.13.2 25 | uvloop==0.14.0 26 | watchgod==0.6 27 | websocket-client==0.57.0 28 | websockets==8.1 29 | yarl==1.6.3 30 | -------------------------------------------------------------------------------- /public/index.js: -------------------------------------------------------------------------------- 1 | const sio = io({ 2 | transportOptions: { 3 | polling: { 4 | extraHeaders: { 5 | 'X-Username': window.location.hash.substring(1) 6 | } 7 | } 8 | } 9 | }); 10 | 11 | sio.on('connect', () => { 12 | console.log('connected'); 13 | sio.emit('sum', {numbers: [1, 2]}, (result) => { 14 | console.log(result); 15 | }); 16 | }); 17 | 18 | sio.on('connect_error', (e) => { 19 | console.log(e.message); 20 | }); 21 | 22 | sio.on('disconnect', () => { 23 | console.log('disconnected'); 24 | }); 25 | 26 | sio.on('mult', (data, cb) => { 27 | const result = data.numbers[0] * data.numbers[1]; 28 | cb(result); 29 | }); 30 | 31 | sio.on('client_count', (count) => { 32 | console.log('There are ' + count + ' connected clients.'); 33 | }); 34 | 35 | sio.on('room_count', (count) => { 36 | console.log('There are ' + count + ' clients in my room.'); 37 | }); 38 | 39 | sio.on('user_joined', (username) => { 40 | console.log('User ' + username + ' has joined.'); 41 | }); 42 | 43 | sio.on('user_left', (username) => { 44 | console.log('User ' + username + ' has left.'); 45 | }); 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Miguel Grinberg 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /async_client.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import socketio 3 | 4 | sio = socketio.AsyncClient() 5 | 6 | 7 | @sio.event 8 | async def connect(): 9 | print('connected') 10 | result = await sio.call('sum', {'numbers': [1, 2]}) 11 | print(result) 12 | 13 | 14 | @sio.event 15 | async def connect_error(e): 16 | print(e) 17 | 18 | 19 | @sio.event 20 | async def disconnect(): 21 | print('disconnected') 22 | 23 | 24 | @sio.event 25 | async def mult(data): 26 | return data['numbers'][0] * data['numbers'][1] 27 | 28 | 29 | @sio.event 30 | async def client_count(count): 31 | print('There are', count, 'connected clients.') 32 | 33 | 34 | @sio.event 35 | async def room_count(count): 36 | print('There are', count, 'clients in my room.') 37 | 38 | 39 | @sio.event 40 | async def user_joined(username): 41 | print('User', username, 'has joined.') 42 | 43 | 44 | @sio.event 45 | async def user_left(username): 46 | print('User', username, 'has left.') 47 | 48 | 49 | async def main(): 50 | await sio.connect('http://localhost:8000', 51 | headers={'X-Username': 'miguel'}) 52 | await sio.wait() 53 | 54 | 55 | asyncio.run(main()) 56 | -------------------------------------------------------------------------------- /client.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import sys 3 | import socketio 4 | 5 | sio = socketio.Client() 6 | 7 | 8 | @sio.event 9 | def connect(): 10 | print('connected') 11 | result = sio.call('sum', {'numbers': [1, 2]}) 12 | print(result) 13 | 14 | 15 | @sio.event 16 | def connect_error(e): 17 | print(e) 18 | 19 | 20 | @sio.event 21 | def disconnect(): 22 | print('disconnected') 23 | 24 | 25 | @sio.event 26 | def mult(data): 27 | return data['numbers'][0] * data['numbers'][1] 28 | 29 | 30 | @sio.event 31 | def client_count(count): 32 | print('There are', count, 'connected clients.') 33 | 34 | 35 | @sio.event 36 | def room_count(count): 37 | print('There are', count, 'clients in my room.') 38 | 39 | 40 | @sio.event 41 | def user_joined(username): 42 | print('User', username, 'has joined.') 43 | 44 | 45 | @sio.event 46 | def user_left(username): 47 | print('User', username, 'has left.') 48 | 49 | 50 | def main(username): 51 | sio.connect('http://localhost:8000', 52 | headers={'X-Username': username}) 53 | sio.wait() 54 | 55 | 56 | if __name__ == '__main__': 57 | main(sys.argv[1] if len(sys.argv) > 1 else None) 58 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | import random 2 | import socketio 3 | 4 | sio = socketio.Server() 5 | app = socketio.WSGIApp(sio, static_files={ 6 | '/': './public/' 7 | }) 8 | client_count = 0 9 | a_count = 0 10 | b_count = 0 11 | 12 | 13 | def task(sid): 14 | sio.sleep(5) 15 | result = sio.call('mult', {'numbers': [3, 4]}, to=sid) 16 | print(result) 17 | 18 | 19 | @sio.event 20 | def connect(sid, environ): 21 | global client_count 22 | global a_count 23 | global b_count 24 | 25 | username = environ.get('HTTP_X_USERNAME') 26 | print('username:', username) 27 | if not username: 28 | return False 29 | 30 | with sio.session(sid) as session: 31 | session['username'] = username 32 | sio.emit('user_joined', username) 33 | 34 | client_count += 1 35 | print(sid, 'connected') 36 | sio.start_background_task(task, sid) 37 | sio.emit('client_count', client_count) 38 | if random.random() > 0.5: 39 | sio.enter_room(sid, 'a') 40 | a_count += 1 41 | sio.emit('room_count', a_count, to='a') 42 | else: 43 | sio.enter_room(sid, 'b') 44 | b_count += 1 45 | sio.emit('room_count', b_count, to='b') 46 | 47 | 48 | @sio.event 49 | def disconnect(sid): 50 | global client_count 51 | global a_count 52 | global b_count 53 | client_count -= 1 54 | print(sid, 'disconnected') 55 | sio.emit('client_count', client_count) 56 | if 'a' in sio.rooms(sid): 57 | a_count -= 1 58 | sio.emit('room_count', a_count, to='a') 59 | else: 60 | b_count -= 1 61 | sio.emit('room_count', b_count, to='b') 62 | 63 | with sio.session(sid) as session: 64 | sio.emit('user_left', session['username']) 65 | 66 | 67 | @sio.event 68 | def sum(sid, data): 69 | result = data['numbers'][0] + data['numbers'][1] 70 | return {'result': result} 71 | -------------------------------------------------------------------------------- /async_app.py: -------------------------------------------------------------------------------- 1 | import random 2 | import socketio 3 | 4 | sio = socketio.AsyncServer(async_mode='asgi') 5 | app = socketio.ASGIApp(sio, static_files={ 6 | '/': './public/' 7 | }) 8 | client_count = 0 9 | a_count = 0 10 | b_count = 0 11 | 12 | 13 | async def task(sid): 14 | await sio.sleep(5) 15 | result = await sio.call('mult', {'numbers': [3, 4]}, to=sid) 16 | print(result) 17 | 18 | 19 | @sio.event 20 | async def connect(sid, environ): 21 | global client_count 22 | global a_count 23 | global b_count 24 | 25 | username = environ.get('HTTP_X_USERNAME') 26 | print('username:', username) 27 | if not username: 28 | return False 29 | 30 | async with sio.session(sid) as session: 31 | session['username'] = username 32 | await sio.emit('user_joined', username) 33 | 34 | client_count += 1 35 | print(sid, 'connected') 36 | sio.start_background_task(task, sid) 37 | await sio.emit('client_count', client_count) 38 | if random.random() > 0.5: 39 | sio.enter_room(sid, 'a') 40 | a_count += 1 41 | await sio.emit('room_count', a_count, to='a') 42 | else: 43 | sio.enter_room(sid, 'b') 44 | b_count += 1 45 | await sio.emit('room_count', b_count, to='b') 46 | 47 | 48 | @sio.event 49 | async def disconnect(sid): 50 | global client_count 51 | global a_count 52 | global b_count 53 | client_count -= 1 54 | print(sid, 'disconnected') 55 | await sio.emit('client_count', client_count) 56 | if 'a' in sio.rooms(sid): 57 | a_count -= 1 58 | await sio.emit('room_count', a_count, to='a') 59 | else: 60 | b_count -= 1 61 | await sio.emit('room_count', b_count, to='b') 62 | 63 | async with sio.session(sid) as session: 64 | await sio.emit('user_left', session['username']) 65 | 66 | 67 | @sio.event 68 | async def sum(sid, data): 69 | result = data['numbers'][0] + data['numbers'][1] 70 | return {'result': result} 71 | --------------------------------------------------------------------------------