Python Networking
Python Network Programming
Section titled “Python Network Programming”Python provides comprehensive support for network programming, ranging from low-level socket access to high-level libraries for common application protocols.
- Low-Level Access: The
socketmodule provides access to the BSD socket interface, allowing direct implementation of clients and servers using TCP (connection-oriented) and UDP (connectionless) protocols. - High-Level Access: Standard libraries offer abstractions for protocols like HTTP (
http.client,urllib.request), FTP (ftplib), SMTP (smtplib), POP3 (poplib), IMAP (imaplib), etc. Third-party libraries likerequestsfurther simplify HTTP interactions.
This chapter focuses on the fundamentals of low-level socket programming using the socket module.
What are Sockets?
Section titled “What are Sockets?”Sockets are the endpoints of a two-way communication link between two programs running on a network. A socket is bound to a port number so that the TCP layer can identify the application that data is destined to be sent to.
Sockets facilitate communication within a single process, between processes on the same machine (using Unix domain sockets or loopback), or between processes on different machines across the internet.
Key Socket Terminology:
| Term | Description |
|---|---|
| Domain (or Family) | Specifies the protocol family. Common values:AF_INET: IPv4 protocols.AF_INET6: IPv6 protocols.AF_UNIX: Unix domain sockets (for local inter-process communication). |
| Type | Specifies the communication semantics. Common values:SOCK_STREAM: Connection-oriented, reliable stream (TCP).SOCK_DGRAM: Connectionless, unreliable datagrams (UDP). |
| Protocol | Usually 0, allowing the system to choose the appropriate protocol based on domain and type (e.g., IPPROTO_TCP for SOCK_STREAM, IPPROTO_UDP for SOCK_DGRAM). |
| Hostname | Identifies a network interface. Can be a domain name (e.g., ‘www.example.com’), an IPv4 address string (e.g., ‘192.168.1.1’), an IPv6 address string, an empty string ('') representing INADDR_ANY (listen on all available interfaces), or 'localhost' / '127.0.0.1' for the loopback interface. |
| Port | A number (0-65535) identifying a specific process or service on a host. Ports 0-1023 are well-known ports usually requiring root/admin privileges. |
The socket Module
Section titled “The socket Module”The core of socket programming in Python is the socket module.
Creating a Socket:
Section titled “Creating a Socket:”Use socket.socket() to create a new socket object.
s = socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0)Common parameters:
family: Socket domain (e.g.,socket.AF_INETfor IPv4).type: Socket type (e.g.,socket.SOCK_STREAMfor TCP,socket.SOCK_DGRAMfor UDP).proto: Protocol number (usually 0).
Using with Statement (Recommended):
Section titled “Using with Statement (Recommended):”Sockets should be closed when no longer needed. The with statement ensures sockets are closed automatically, similar to file handling.
import socket
try: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: # Use the socket 's' here print("Socket created successfully.") # Socket 's' will be closed automatically upon exiting the 'with' blockexcept socket.error as err: print(f"Socket creation failed with error: {err}")Essential Socket Methods:
Section titled “Essential Socket Methods:”Server Socket Methods (TCP):
Section titled “Server Socket Methods (TCP):”| Method | Description |
|---|---|
s.bind((host, port)) | Binds the socket to a specific network interface (host) and port number. |
s.listen(backlog) | Enables the server to accept connections. backlog specifies the maximum number of queued connections. |
s.accept() | Waits for an incoming client connection. Returns a tuple (conn, addr) where conn is a new socket object for communication with the client, and addr is the client’s address tuple. |
Client Socket Methods (TCP):
Section titled “Client Socket Methods (TCP):”| Method | Description |
|---|---|
s.connect((host, port)) | Connects the client socket to a server at host and port. |
General Socket Methods (TCP & UDP):
Section titled “General Socket Methods (TCP & UDP):”| Method | Description |
|---|---|
s.send(bytes) | Transmits TCP data. Data must be bytes. Returns the number of bytes sent. |
s.recv(bufsize) | Receives TCP data. bufsize is the maximum amount of data (in bytes) to receive at once. Returns received data as bytes. |
s.sendall(bytes) | Transmits all data in bytes for TCP. Handles potential short sends. |
s.sendto(bytes, address) | Transmits UDP datagram (bytes) to the specified address tuple (host, port). |
s.recvfrom(bufsize) | Receives UDP datagram. Returns a tuple (bytes, address) where bytes is the data and address is the sender’s address. |
s.close() | Closes the socket. Automatically handled by with statement. |
socket.gethostname() | Returns the standard hostname for the local machine. |
Important: In Python 3, socket methods send(), recv(), sendto(), and recvfrom() operate on bytes objects, not strings. You must encode strings to bytes before sending and decode bytes to strings after receiving.
A Simple TCP Echo Server
Section titled “A Simple TCP Echo Server”This server listens on a specific port, accepts client connections, reads data from the client, and sends the same data back (echoes it).
#!/usr/bin/env python3import socket
HOST = '127.0.0.1' # Standard loopback interface address (localhost)PORT = 65432 # Port to listen on (non-privileged ports are > 1023)
def run_server(): # Use 'with' statement for automatic socket closing with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: try: s.bind((HOST, PORT)) s.listen() print(f"Server listening on {HOST}:{PORT}")
# Wait for a connection conn, addr = s.accept() # Blocking call
# Use 'with' for the client connection socket as well with conn: print(f"Connected by {addr}") while True: # Receive data (up to 1024 bytes) data = conn.recv(1024) if not data: # If recv returns empty bytes, client closed connection print(f"Client {addr} disconnected.") break
# Decode received bytes to string for printing print(f"Received from {addr}: {data.decode('utf-8')}")
# Echo data back to client (encode string to bytes) conn.sendall(data) print(f"Echoed back to {addr}")
except socket.error as e: print(f"Socket error: {e}") except KeyboardInterrupt: print("\nServer shutting down.")
if __name__ == "__main__": run_server()A Simple TCP Echo Client
Section titled “A Simple TCP Echo Client”This client connects to the server, sends a message, and prints the echoed response.
#!/usr/bin/env python3import socket
HOST = '127.0.0.1' # The server's hostname or IP addressPORT = 65432 # The port used by the server
def run_client(message): try: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) print(f"Connected to server {HOST}:{PORT}")
# Encode the message to bytes before sending message_bytes = message.encode('utf-8') s.sendall(message_bytes) print(f"Sent: {message}")
# Receive the echoed data data = s.recv(1024) # Decode the received bytes to string received_message = data.decode('utf-8') print(f"Received echo: {received_message}")
except socket.error as e: print(f"Socket error: {e}") except ConnectionRefusedError: print(f"Connection refused. Is the server running on {HOST}:{PORT}?")
if __name__ == "__main__": message_to_send = "Hello, Server!" run_client(message_to_send)Running the Server and Client:
Section titled “Running the Server and Client:”- Open a terminal and run the server:
python server.py - Open another terminal and run the client:
python client.py
Server Output:
Server listening on 127.0.0.1:65432Connected by ('127.0.0.1', <client_port>)Received from ('127.0.0.1', <client_port>): Hello, Server!Echoed back to ('127.0.0.1', <client_port>)Client ('127.0.0.1', <client_port>) disconnected.Client Output:
Connected to server 127.0.0.1:65432Sent: Hello, Server!Received echo: Hello, Server!Python High-Level Internet Modules
Section titled “Python High-Level Internet Modules”Python’s standard library includes modules for common internet protocols:
| Protocol | Primary Use | Common Port(s) | Python Module(s) |
|---|---|---|---|
| HTTP/HTTPS | Web access | 80, 443 | urllib.request, http.client (Lower level). requests (Third-party, recommended) |
| FTP | File transfer | 21 | ftplib |
| SMTP | Sending email | 25, 587, 465 | smtplib |
| POP3 | Fetching email | 110, 995 | poplib |
| IMAP4 | Fetching email | 143, 993 | imaplib |
| NNTP | Usenet news | 119, 563 | nntplib |
| Telnet | Remote login | 23 | telnetlib |
| XML-RPC | Remote procedure calls | Varies | xmlrpc.client, xmlrpc.server |
For web interactions (HTTP/HTTPS), the third-party requests library is widely used and generally preferred over urllib for its simpler API.
Further Learning
Section titled “Further Learning”Socket programming is a deep topic. Explore these resources:
- Python Official
socketModule Documentation: https://docs.python.org/3/library/socket.html - Python Socket Programming HOWTO: https://docs.python.org/3/howto/sockets.html
- Beej’s Guide to Network Programming (General C guide, concepts apply): https://beej.us/guide/bgnet/