Socket Programming - Simple Client & Server
Sockets and the socket API are used to send messages across a network.
Let’s focus on building simple echo client and server using TCP socket.
What are TCP Sockets?
TCP(Transmission Control Protocol) is reliable and has in-order data delivery. Here we’re going to create a socket object using socket.socket() and specify the socket type as socket.SOCK_STREAM.
btw, UDP(User Datagram Protocol) sockets created with socket.SOCK_DGRAM aren’t reliable, and data read by the receiver can be out-of-order.
The sequence of socket API calls and data flow for TCP:
The Server:
- socket()
- bind()
- listen()
- accept()
server start listening…
The Client:
- socket()
- connect()
establish a connection to the server and initiate the three-way handshake.
Create Echo Client & Server
Server
#!/usr/bin/env python3
import socket
HOST = "127.0.0.1"
PORT = 4444 # whatever you want(>1023)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
print("Connected by", addr)
while True:
data = conn.recv(1024)
if not data:
break
conn.sendall(data)
explanation:
- with statement helps you close() automatically.
- AF_INET is the Internet address family for IPv4.
- SOCK_STREAM is the socket type for TCP.
- bind() is used to associate the socket with a specific network interface and port number. It expects a 2-tuple like (host, port).
- listen() enables a server to accept() connections.
- accept() blocks and waits for an incoming connection. When a client connects, it returns a new socket object.
- An infinite while loop is used to loop over blocking calls to conn.recv(). And then echoes back using conn.sendall().
Client
#!/usr/bin/env python3
import socket
HOST = "127.0.0.1"
PORT = 4444
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
s.sendall(b"Hello friend")
data = s.recv(1024)
print("Received", repr(data))
run the server and client
$ ./echo-server.py
Connected by ('127.0.0.1', 47060)
-------------------------------------------
it will appear to hang because of accept()
open another terminal
-------------------------------------------
$ ./echo-client.py
Received b'Hello friend'
When server is running…
Use netstat to view socket state:
$ netstat -an | grep 4444
tcp 0 0 127.0.0.1:4444 0.0.0.0:* LISTEN
Use lsof(list open files) to view state:
$ lsof -i -n
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
python3 12332 shylock 3u IPv4 375130 0t0 TCP 127.0.0.1:4444 (LISTEN)
When there’s no listening socket…
- maybe port number is wrong
- maybe server isn’t running
- maybe there’s a firewall
$ ./echo-client.py
Traceback (most recent call last):
File "./echo-client.py", line 9, in <module>
s.connect((HOST, PORT))
ConnectionRefusedError: [Errno 111] Connection refused
Why 127.0.0.1? What’s the loopback interface?
The loopback interface is contained inside the host. When you’re using it, data never leaves the host. The loopback interface and IP address 127.0.0.1 or ::1 referred to as “localhost”.
ref: