Sockets as Application Abstractions
To enable inter-process communication across a network, every active process must possess a unique identifier. Sockets serve as the fundamental mechanism for this exchange. Functionally, a socket operates as an abstraction layer situated between the Application Layer and the Transport Layer of the network stack. By encapsulating the complexities of the TCP/IP suite, sockets expose simplified interfaces that developers utilize to manage data transmission.
There are distinct familise of sockets categorized by their scope:
- Local Communication: Identified as
AF_UNIX, utilized for interactions within the same machine. - Network Communication: Identified as
AF_INET, designed for IP-based communications over networks.
TCP-Based Socket Implementation
The Transmission Control Protocol (TCP) is connection-oriented. Communication typically initiates when a client requests a connection from a listening server. The following example demonstrates a basic server-client interaction.
Server-Side Logic
import socket
# Establish the socket instance
# Family: IPv4, Type: Stream (TCP)
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Assign local host and port
host = '127.0.0.1'
port = 8000
server_sock.bind((host, port))
# Begin accepting incoming connections (Queue size: 5)
server_sock.listen(5)
print("Server started, waiting for connections...")
try:
# Block until a client connects
conn, addr = server_sock.accept()
print(f"Connected by {addr}")
# Receive payload (Bytes limit: 1024)
data = conn.recv(1024)
# Echo back modified data
if data:
response = data.upper()
conn.sendall(response)
finally:
conn.close()
server_sock.close()
Client-Side Logic
import socket
# Create client socket
cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
target_host = '127.0.0.1'
target_port = 8000
# Initiate connection
cli_sock.connect((target_host, target_port))
# Transmit UTF-8 encoded string
msg = "hello"
cli_sock.send(msg.encode('utf-8'))
# Capture response
resp = cli_sock.recv(1024)
print(f"Server Reply: {resp.decode('utf-8')}")
cli_sock.close()
Establishing Continuous Communication Loops
Basic single-request models are often insufficient. Real-world applications require persistent sessions allowing multiple exchanges before termination. This requires wrapping the accept and receive/send logic within event loops.
import socket
def run_server():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('0.0.0.0', 9090))
s.listen(10)
print("Listening on 9090...")
while True:
try:
conn, addr = s.accept()
print(f"New connection from {addr}")
while True:
buffer = conn.recv(1024)
if not buffer:
break
msg = buffer.decode().upper()
print(f"Received: {msg}")
# Send processed response
conn.send(msg.encode())
except Exception as e:
print(f"Error occurred: {e}")
finally:
conn.close()
if __name__ == "__main__":
run_server()
The corresponding client script must also implement a loop to facilitate continuous interaction rather than sending a single packet.
def run_client():
c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.connect(('localhost', 9090))
while True:
user_input = input("Enter message > ")
if not user_input:
break
c.send(user_input.encode('utf-8'))
response = c.recv(1024)
print(f"Response: {response.decode()}")
run_client()
UDP Protocol Implementation
Unlike TCP, the User Datagram Protocol (UDP) is connectionless. It prioritizes speed over reliability. Data is sent via datagrams without establishing a persistent session. In Python, the socket type changes to SOCK_DGRAM.
UDP Server
import socket
u_server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
u_server.bind(('127.0.0.1', 7777))
while True:
# recvfrom returns tuple (data, address)
data, client_ip = u_server.recvfrom(1024)
print(f"From {client_ip}: {data}")
# Send response directly to the sender's address
u_server.sendto(data.upper(), client_ip)
UDP Client
u_cli = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
dest_addr = ('127.0.0.1', 7777)
while True:
msg = input("Type message > ")
u_cli.sendto(msg.encode('utf-8'), dest_addr)
res, _ = u_cli.recvfrom(1024)
print(f"Got: {res}")
u_cli.close()