|
| 1 | +The Socket.IO Client |
| 2 | +==================== |
| 3 | + |
| 4 | +This package contains two Socket.IO clients: |
| 5 | + |
| 6 | +- The :func:`socketio.Client` class creates a client compatible with the |
| 7 | + standard Python library. |
| 8 | +- The :func:`socketio.AsyncClient` class creates a client compatible with |
| 9 | + the ``asyncio`` package. |
| 10 | + |
| 11 | +The methods in the two clients are the same, with the only difference that in |
| 12 | +the ``asyncio`` client most methods are implemented as coroutines. |
| 13 | + |
| 14 | +Installation |
| 15 | +------------ |
| 16 | + |
| 17 | +To install the standard Python client along with its dependencies, use the |
| 18 | +following command:: |
| 19 | + |
| 20 | + pip install "python-socketio[client]" |
| 21 | + |
| 22 | +If instead you plan on using the ``asyncio`` client, then use this:: |
| 23 | + |
| 24 | + pip install "python-socketio[asyncio_client]" |
| 25 | + |
| 26 | +Creating a Client Instance |
| 27 | +-------------------------- |
| 28 | + |
| 29 | +To instantiate an Socket.IO client, simply create an instance of the |
| 30 | +appropriate client class:: |
| 31 | + |
| 32 | + import socketio |
| 33 | + |
| 34 | + # standard Python |
| 35 | + sio = socketio.Client() |
| 36 | + |
| 37 | + # asyncio |
| 38 | + sio = socketio.AsyncClient() |
| 39 | + |
| 40 | +Defining Event Handlers |
| 41 | +----------------------- |
| 42 | + |
| 43 | +To responds to events triggered by the connection or the server, event Handler |
| 44 | +functions must be defined using the ``on`` decorator:: |
| 45 | + |
| 46 | + @sio.on('connect') |
| 47 | + def on_connect(): |
| 48 | + print('I'm connected!') |
| 49 | + |
| 50 | + @sio.on('message') |
| 51 | + def on_message(data): |
| 52 | + print('I received a message!') |
| 53 | + |
| 54 | + @sio.on('my message') |
| 55 | + def on_message(data): |
| 56 | + print('I received a custom message!') |
| 57 | + |
| 58 | + @sio.on('disconnect') |
| 59 | + def on_disconnect(): |
| 60 | + print('I'm disconnected!') |
| 61 | + |
| 62 | +For the ``asyncio`` server, event handlers can be regular functions as above, |
| 63 | +or can also be coroutines:: |
| 64 | + |
| 65 | + @sio.on('message') |
| 66 | + async def on_message(data): |
| 67 | + print('I received a message!') |
| 68 | + |
| 69 | +The argument given to the ``on`` decorator is the event name. The predefined |
| 70 | +events that are supported are ``connect``, ``message`` and ``disconnect``. The |
| 71 | +application can define any other desired event names. |
| 72 | + |
| 73 | +Note that the ``disconnect`` handler is invoked for application initiated |
| 74 | +disconnects, server initiated disconnects, or accidental disconnects, for |
| 75 | +example due to networking failures. In the case of an accidental disconnection, |
| 76 | +the client is going to attempt to reconnect immediately after invoking the |
| 77 | +disconnect handler. As soon as the connection is re-established the connect |
| 78 | +handler will be invoked once again. |
| 79 | + |
| 80 | +The ``data`` argument passed to the ``'message'`` and custom event Handlers |
| 81 | +contains application-specific data provided by the server. |
| 82 | + |
| 83 | +Connecting to a Server |
| 84 | +---------------------- |
| 85 | + |
| 86 | +The connection to a server is established by calling the ``connect()`` |
| 87 | +method:: |
| 88 | + |
| 89 | + sio.connect('http://localhost:5000') |
| 90 | + |
| 91 | +In the case of the ``asyncio`` client, the method is a coroutine:: |
| 92 | + |
| 93 | + await sio.connect('http://localhost:5000') |
| 94 | + |
| 95 | +Emitting Events |
| 96 | +--------------- |
| 97 | + |
| 98 | +The client can emit an event to the server using the ``emit()`` method:: |
| 99 | + |
| 100 | + sio.emit('my message', {'foo': 'bar'}) |
| 101 | + |
| 102 | +Or in the case of ``asyncio``, as a coroutine:: |
| 103 | + |
| 104 | + await sio.emit('my message', {'foo': 'bar'}) |
| 105 | + |
| 106 | +The single argument provided to the method is the data that is passed on |
| 107 | +to the server. The data can be of type ``str``, ``bytes``, ``dict`` or |
| 108 | +``list``. The data included inside dictionaries and lists is also |
| 109 | +constrained to these types. |
| 110 | + |
| 111 | +The ``emit()`` method can be invoked inside an event handler as a response |
| 112 | +to a server event, or in any other part of the application, including in |
| 113 | +background tasks. |
| 114 | + |
| 115 | +For convenience, a ``send()`` method is also provided. This method accepts |
| 116 | +a data element as its only argument, and emits the standard ``message`` |
| 117 | +event with it:: |
| 118 | + |
| 119 | + sio.send('some data') |
| 120 | + |
| 121 | +In the case of ``asyncio``, ``send()`` is a coroutine:: |
| 122 | + |
| 123 | + await sio.send('some data') |
| 124 | + |
| 125 | +Event Callbacks |
| 126 | +--------------- |
| 127 | + |
| 128 | +When a server emits an event to a client, it can optionally provide a |
| 129 | +callback function, to be invoked as a way of acknowledgment that the server |
| 130 | +has processed the event. While this is entirely managed by the server, the |
| 131 | +client can provide a list of return values that are to be passed on to the |
| 132 | +callback function set up by the server. This is achieves simply by returning |
| 133 | +the desired values from the handler function:: |
| 134 | + |
| 135 | + @sio.on('my event', namespace='/chat') |
| 136 | + def my_event_handler(sid, data): |
| 137 | + # handle the message |
| 138 | + return "OK", 123 |
| 139 | + |
| 140 | +Likewise, the client can request a callback function to be invoked after the |
| 141 | +server has processed an event. The :func:`socketio.Server.emit` method has an |
| 142 | +optional ``callback`` argument that can be set to a callable. If this |
| 143 | +argument is given, the callable will be invoked after the server has processed |
| 144 | +the event, and any values returned by the server handler will be passed as |
| 145 | +arguments to this function. |
| 146 | + |
| 147 | +Namespaces |
| 148 | +---------- |
| 149 | + |
| 150 | +The Socket.IO protocol supports multiple logical connections, all multiplexed |
| 151 | +on the same physical connection. Clients can open multiple connections by |
| 152 | +specifying a different *namespace* on each. Namespaces use a path syntax |
| 153 | +starting with a forward slash. A list of namespaces can be given by the client |
| 154 | +in the ``connect()`` call. For example, this example creates two logical |
| 155 | +connections, the default one plus a second connection under the ``/chat`` |
| 156 | +namespace:: |
| 157 | + |
| 158 | + sio.connect('http://localhost:5000', namespaces=['/chat']) |
| 159 | + |
| 160 | +To define event handlers on a namespace, the ``namespace`` argument must be |
| 161 | +added to the ``on`` decorator:: |
| 162 | + |
| 163 | + @sio.on('connect', namespace='/chat') |
| 164 | + def on_connect(): |
| 165 | + print('I'm connected to the /chat namespace!') |
| 166 | + |
| 167 | +Likewise, the client can emit an event to the server on a namespace by |
| 168 | +providing its in the ``emit()`` call:: |
| 169 | + |
| 170 | + sio.emit('my message', {'foo': 'bar'}, namespace='/chat') |
| 171 | + |
| 172 | +If the ``namespaces`` argument of the ``connect()`` call isn't given, any |
| 173 | +namespaces used in event handlers are automatically connected. |
| 174 | + |
| 175 | +Class-Based Namespaces |
| 176 | +---------------------- |
| 177 | + |
| 178 | +As an alternative to the decorator-based event handlers, the event handlers |
| 179 | +that belong to a namespace can be created as methods of a subclass of |
| 180 | +:class:`socketio.ClientNamespace`:: |
| 181 | + |
| 182 | + class MyCustomNamespace(socketio.ClientNamespace): |
| 183 | + def on_connect(self): |
| 184 | + pass |
| 185 | + |
| 186 | + def on_disconnect(self): |
| 187 | + pass |
| 188 | + |
| 189 | + def on_my_event(self, data): |
| 190 | + self.emit('my_response', data) |
| 191 | + |
| 192 | + sio.register_namespace(MyCustomNamespace('/chat')) |
| 193 | + |
| 194 | +For asyncio based severs, namespaces must inherit from |
| 195 | +:class:`socketio.AsyncClientNamespace`, and can define event handlers as |
| 196 | +coroutines if desired:: |
| 197 | + |
| 198 | + class MyCustomNamespace(socketio.AsyncClientNamespace): |
| 199 | + def on_connect(self): |
| 200 | + pass |
| 201 | + |
| 202 | + def on_disconnect(self): |
| 203 | + pass |
| 204 | + |
| 205 | + async def on_my_event(self, data): |
| 206 | + await self.emit('my_response', data) |
| 207 | + |
| 208 | + sio.register_namespace(MyCustomNamespace('/chat')) |
| 209 | + |
| 210 | +When class-based namespaces are used, any events received by the client are |
| 211 | +dispatched to a method named as the event name with the ``on_`` prefix. For |
| 212 | +example, event ``my_event`` will be handled by a method named ``on_my_event``. |
| 213 | +If an event is received for which there is no corresponding method defined in |
| 214 | +the namespace class, then the event is ignored. All event names used in |
| 215 | +class-based namespaces must use characters that are legal in method names. |
| 216 | + |
| 217 | +As a convenience to methods defined in a class-based namespace, the namespace |
| 218 | +instance includes versions of several of the methods in the |
| 219 | +:class:`socketio.Client` and :class:`socketio.AsyncClient` classes that |
| 220 | +default to the proper namespace when the ``namespace`` argument is not given. |
| 221 | + |
| 222 | +In the case that an event has a handler in a class-based namespace, and also a |
| 223 | +decorator-based function handler, only the standalone function handler is |
| 224 | +invoked. |
| 225 | + |
| 226 | +Disconnecting from the Server |
| 227 | +----------------------------- |
| 228 | + |
| 229 | +At any time the client can request to be disconnected from the server by |
| 230 | +invoking the ``disconnect()`` method:: |
| 231 | + |
| 232 | + sio.disconnect() |
| 233 | + |
| 234 | +For the ``asyncio`` client this is a coroutine:: |
| 235 | + |
| 236 | + await sio.disconnect() |
| 237 | + |
| 238 | +Managing Background Tasks |
| 239 | +------------------------- |
| 240 | + |
| 241 | +When a client connection to the server is established, a few background |
| 242 | +tasks will be spawned to keep the connection alive and handle incoming |
| 243 | +events. The application running on the main thread is free to do any |
| 244 | +work, as this is not going to prevent the functioning of the Socket.IO |
| 245 | +client. |
| 246 | + |
| 247 | +If the application does not have anything to do in the main thread and |
| 248 | +just wants to wait until the connection with the server ends, it can call |
| 249 | +the ``wait()`` method:: |
| 250 | + |
| 251 | + sio.wait() |
| 252 | + |
| 253 | +Or in the ``asyncio`` version:: |
| 254 | + |
| 255 | + await sio.wait() |
| 256 | + |
| 257 | +For the convenience of the application, a helper function is provided to |
| 258 | +start a custom background task:: |
| 259 | + |
| 260 | + def my_background_task(my_argument) |
| 261 | + # do some background work here! |
| 262 | + pass |
| 263 | + |
| 264 | + sio.start_background_task(my_background_task, 123) |
| 265 | + |
| 266 | +The arguments passed to this method are the background function and any |
| 267 | +positional or keyword arguments to invoke the function with. |
| 268 | + |
| 269 | +Here is the ``asyncio`` version:: |
| 270 | + |
| 271 | + async def my_background_task(my_argument) |
| 272 | + # do some background work here! |
| 273 | + pass |
| 274 | + |
| 275 | + sio.start_background_task(my_background_task, 123) |
| 276 | + |
| 277 | +Note that this function is not a coroutine, since it does not wait for the |
| 278 | +background function to end. The background function must be a coroutine. |
| 279 | + |
| 280 | +The ``sleep()`` method is a second convenince function that is provided for |
| 281 | +the benefit of applications working with background tasks of their own:: |
| 282 | + |
| 283 | + sio.sleep(2) |
| 284 | + |
| 285 | +Or for ``asyncio``:: |
| 286 | + |
| 287 | + await sio.sleep(2) |
| 288 | + |
| 289 | +The single argument passed to the method is the number of seconds to sleep |
| 290 | +for. |
0 commit comments