In this topic of study, we examine the basics of how to write a network server in Python. To use one of my favorite idioms, this topic is the biggest can of worms that we tackle in this course. That is to say, there are some really complex issues with servers. We will identify some of those issues and will talk about strategies for writing useful programs without getting drug into theoretical computer science research.
A server is program that listens and accepts connections on a particular TCP or UDP port and provides information or services to the connecting clients. A server typically will run continuously as a background process; and more importantly, it does not impose limits on the number of simultaneous connections that can be served.
I thought we already did servers?
Well, yes, we did already write programs that use sockets to listen on a port and accept connections; but that server could only accept one connection at a time. A server must be able to handle many clients at one time. This matter of dealing with multiple clients at once is what makes server programs complex.
Three basic approaches are used to solve this problem.
- Process creation with forks
- Asynchronous I/O
We will pretty much skip the first of these options (see Chapter 20 – Forking) because it does not work on Windows platforms and is of limited value on Unix based systems. In addition, we will also discuss situations where the best design is a hybrid solution, which uses both multi-threaded and asynchronous techniques. (see Combined Asynchronous and Threaded Servers)