This guide shows you how to create a simple TCP client-server pair in Python to send and receive text data. You’ll write two scripts: a server that listens for connections and echoes back what it receives, and a client that connects, sends a message, and prints the response. No external libraries are needed—just Python’s built-in socket module.
What You’ll Need
- Python 3.6 or newer installed on your machine.
- Basic familiarity with running Python scripts from the terminal.
- Two terminal windows (or two machines on the same network) to test the client and server.
Step-by-Step
-
Create the server script. Open a text editor and create a file named
server.py. This script will bind to a port, listen for incoming connections, and handle each client in a loop. -
Write the server code. Copy the following into
server.py:import socket HOST = '127.0.0.1' # localhost PORT = 65432 # non-privileged port with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((HOST, PORT)) s.listen() print('Server listening on', HOST, PORT) conn, addr = s.accept() with conn: print('Connected by', addr) while True: data = conn.recv(1024) if not data: break print('Received:', data.decode()) conn.sendall(data) # echo back -
Create the client script. Create another file named
client.pyin the same directory. -
Write the client code. Copy the following into
client.py:import socket HOST = '127.0.0.1' PORT = 65432 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) s.sendall(b'Hello, server!') data = s.recv(1024) print('Received', repr(data)) -
Run the server. In the first terminal, run
python server.py. You should see “Server listening on 127.0.0.1 65432”. The script will block waiting for a connection. -
Run the client. In the second terminal, run
python client.py. The client will connect, send the message, and print the echoed response. The server terminal will show the received message and then exit after the client closes the connection. -
Extend to multiple messages. The current server handles only one connection. To accept multiple clients, wrap the accept-and-handle part in an outer loop. For example:
while True: conn, addr = s.accept() with conn: print('Connected by', addr) while True: data = conn.recv(1024) if not data: break conn.sendall(data) -
Send multiple messages from the client. To send more than one message, keep the connection open and use a loop. For example:
with socket.socket(...) as s: s.connect((HOST, PORT)) for msg in [b'First', b'Second']: s.sendall(msg) print(s.recv(1024)) -
Handle larger data. The
recv(1024)call receives at most 1024 bytes at once. For larger messages, you need to loop until all data is received. A simple approach is to send the message length first, then the data, and read until you have that many bytes. Or, for text, send a newline terminator and read until you see it.
Common Mistakes
- Using
send()instead ofsendall().send()may send only part of the data;sendall()keeps sending until all data is sent. Always usesendall()for reliability. - Forgetting to decode bytes. Data over sockets is bytes. Use
.decode()when printing or processing text, and.encode()when sending strings. - Binding to a port already in use. If you get “Address already in use”, the previous server didn’t close properly. Wait a few seconds or use
SO_REUSEADDR(see Tips). - Assuming
recv()gets the whole message. TCP is a stream, not a message boundary. A singlerecv()may return partial data or multiple messages combined. You need to define your own framing (e.g., message length prefix).
Tips
- Set a timeout on the socket to avoid hanging forever:
s.settimeout(5)will raise asocket.timeoutexception if no data arrives within 5 seconds. - Use
withstatements for sockets to ensure they are closed properly. - To allow the server to restart quickly, set
SO_REUSEADDRbefore binding:s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - For production, use threading or asyncio to handle multiple clients concurrently. The simple loop above blocks on
accept()and then onrecv(), so it can’t handle a second client while handling the first. - When sending text, always encode to UTF-8 explicitly:
msg.encode('utf-8').
Troubleshooting
- Connection refused. The server isn’t running, or the port is wrong. Check that the server is listening (you should see the “Server listening” message) and that both scripts use the same port.
- No output from server. The server may be stuck on
accept()waiting for a connection. Ensure the client is running and the IP/port match. - Address already in use. The previous server process is still holding the port. Wait a few seconds or kill the process. On Linux/macOS, you can use
lsof -i :65432to find the PID. - Client sends but server doesn’t receive. Check for firewalls. On Windows, you may need to allow Python through the firewall. On Linux, ensure the port isn’t blocked.
- Data appears garbled. Likely an encoding mismatch. Ensure both sides use the same encoding (UTF-8 is standard).
- Client hangs on
recv(). The server may have closed the connection without sending data. In that case,recv()returns an empty bytes object, which you should check for and break out of the loop.
Frequently Asked Questions
- What is the difference between TCP and UDP? TCP is connection-oriented and guarantees delivery and order; UDP is connectionless and does not guarantee delivery or order. For most data where reliability matters, use TCP.
- How do I send JSON data? Convert the dictionary to a JSON string with
json.dumps(), encode it, and send it. On the receiving side, decode and then usejson.loads(). - Can I use sockets across different machines? Yes. Replace
HOSTwith the server’s IP address (e.g.,192.168.1.10) and ensure the port is open in the server’s firewall. - How do I handle multiple clients at once? Use the
threadingmodule: spawn a new thread for each accepted connection, or useasynciofor asynchronous I/O. - Why does
recv()return less data than I sent? TCP is a stream;recv()returns whatever is currently available, up to the buffer size. You must loop until you have all the data, based on a length prefix or a delimiter. - What is the maximum message size I can send? There is no hard limit, but practically you should break large data into chunks. The socket buffer size is typically 64KB, but you can send more by looping with
sendall().
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.
More cards in this drawer
- Don’t Trust Emails from Duolingo? Real Risks
- Project Blue Lock 2 Codes? Real Status & How to Get Them
- How to Use Kami with Google Classroom
- RPCS3 Settings for Stable Performance & Fewer Stutters
- Recover Deleted LibreOffice Documents
- Why I Use Encrypted DNS: Real Reasons