Handling Multiple Sockets
00:00 In the previous lesson, I revealed the limitation of our bork server. In this lesson, I’ll show you one way of dealing with multiple sockets at a time.
00:09 A single CPU in your machine can only do a single thing at a time, so if you want to listen on multiple sockets, you have to get around this limitation somehow.
00:18
You can use threads or coroutines or even multiple processes if you like, but there’s another choice when it comes to sockets, which is called IO multiplexing, and you can do that in Python with the selectors
module.
00:33 Even before multiprocessor machines, it looked like your computer was doing several things at once because it switched back and forth between things quite quickly.
00:41 A selector is an abstraction that helps you do this. For it to work, you make non-blocking calls on your socket, and then the selector switches back and forth between your sockets.
00:52 Each time your socket gets its turn, a callback is triggered. Inside that callback, you get told whether it is time for reading or time for writing. You then perform read actions on the read event and write actions on the write event.
01:06 There are actually several kinds of selectors in Python, and the kind you want is determined by your OS, but you don’t have to think about that. Python provides the default selector, which chooses the right one for you.
01:19 When you register your socket with a selector, you can associate data with it, which gets passed to you during the callback. This is how you keep state between multiplexed calls.
01:31 Let’s walk through how this works.
01:33 First off, someone makes a connection. Your selector sees this as a new thing. In this initial phase, the selector code is responsible for accepting a new connection and registering it with the multiplexer.
01:46 During the registration process, you create an object to store state and associate it with the connection. Periodically, the selector will send a read event.
01:55 When your code gets this event, it should do any reading it needs to. There may or may not be data on the socket at this time. Likewise, periodically the selector will send a write event.
02:07 When your code gets this event, it should do any writing it needs to. There may or may not be data to write to the socket at this time.
02:15 Let’s say that on a read event, you get some data. Since your program wants to echo that data back out, it first needs to store it in your state for the next write call.
02:26 Then when the write event happens, since there’s something to write in our state object, you echo the borkified data back down the socket, then clear the state object so you don’t do this twice.
02:39 You keep doing this for as long as the connection is there. In your read code, you’ll want to detect if the connection has been closed, and if so, deregister with the selector before closing the socket.
02:51 And since you’re using an IO multiplexer, at any time, a new connection can be made to the selector. That starts up the initialization code for a new socket, which is independent of your previous one.
03:04 The selector then switches back and forth between read and write events for every registered socket.
03:11 In the next lesson, I’ll show you some code that does exactly this.
Become a Member to join the conversation.