The socket APIs are blocking by default. When you use accept() to wait for an incoming connection, your program's execution is blocked until a new incoming connection is actually available. When you use recv() to read incoming data, your program's execution blocks until new data is actually available.
In the last chapter, we built a simple TCP server. This server only accepted one connection, and it only read data from that connection once. Blocking wasn't a problem then, because our server had no other purpose than to serve its one and only client.
In the general case, though, blocking I/O can be a significant problem. Imagine that our server from Chapter 2, Getting to Grips with Socket APIs, needed to serve multiple clients. Then, imagine that one slow client connected to it. Maybe this slow client takes a minute before sending its first data. During this minute, our server would simply be waiting on the recv() call to return. If other clients were trying to connect, they would have to wait it out.
Blocking on recv() like this isn't really acceptable. A real application usually needs to be able to manage several connections simultaneously. This is obviously true on the server side, as most servers are built to manage many connected clients. Imagine running a website where hundreds of clients are connected at once. Serving these clients one at a time would be a non-starter.
Blocking also isn't usually acceptable on the client side either. If you imagine building a fast web browser, it needs to be able to download many images, scripts, and other resources in parallel. Modern web browsers also have a tab feature where many whole web pages can be loaded in parallel.
What we need is a technique for handling many separate connections simultaneously.