学 Python 网络编程时,最容易被 TCP、UDP、IP、端口这些名词劝退,但真正上手时,先抓住 socket 这一层就够了。下面直接用 Python 标准库搭一个可运行的服务端和客户端,把 TCP、UDP 的收发流程走一遍,再结合常见报错和扩展方向,帮你建立最基础也最实用的判断框架。
Socket 是什么,TCP 和 UDP 有什么区别
可以把 Socket 理解成两个程序之间建立通信的入口。只要知道目标的 IP 地址和端口号,程序就能借助它发送和接收数据。
在 Python 里,最常见的网络通信协议主要有两种:
- TCP:面向连接,强调可靠传输。数据按顺序到达,丢包后也会处理,适合文件传输、聊天软件这类不能乱序或丢消息的场景。
- UDP:无连接,发送开销更小,速度通常更快,但不保证一定送达,也不保证顺序,适合直播、语音通话、广播等更看重实时性的场景。
Python 内置的 socket 模块同时支持这两种协议,而且不用额外安装。只要已经掌握 Python 基础语法,就可以直接开始。
用最小示例跑通 TCP 通信
对初学者来说,TCP 更适合作为入门。它的流程清楚,服务端和客户端各自做什么也比较容易看懂。

基本流程如下:
- 服务端:创建 socket → 绑定 IP 和端口
bind→ 开始监听listen→ 等待连接accept→ 收发数据 - 客户端:创建 socket → 连接服务端
connect→ 收发数据
TCP 服务端代码:server.py
import socket
# 1. 创建TCP套接字 SOCK_STREAM代表TCP
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 绑定地址与端口,0.0.0.0代表监听本机所有网卡
HOST = "0.0.0.0"
PORT = 8888
server_socket.bind((HOST, PORT))
# 3. 开启监听,参数为允许等待的最大连接数
server_socket.listen(5)
print(f"服务端启动成功,监听端口:{PORT}")
# 4. 循环等待客户端接入
while True:
# accept()阻塞,直到有客户端连接
conn, addr = server_socket.accept()
print(f"新客户端接入:{addr}")
# 接收客户端数据,缓冲区大小1024字节
data = conn.recv(1024)
if not data:
conn.close()
continue
print("收到客户端消息:", data.decode("utf-8"))
# 向客户端发送响应
resp = "服务端已收到你的消息!"
conn.send(resp.encode("utf-8"))
# 关闭当前客户端连接
conn.close()
这段代码做了几件关键的事:
- 使用
socket.AF_INET表示基于 IPv4 通信。 - 使用
socket.SOCK_STREAM表示采用 TCP。 - 把服务端绑定到
0.0.0.0:8888,意味着监听本机所有网卡上的 8888 端口。 accept()会阻塞等待客户端接入,收到连接后返回连接对象conn和客户端地址addr。recv(1024)读取最多 1024 字节的数据,收到后用decode("utf-8")解码为字符串。
TCP 客户端代码:client.py
import socket
# 创建TCP套接字
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务端地址
HOST = "127.0.0.1"
PORT = 8888
client_socket.connect((HOST, PORT))
# 发送数据,socket只能传输字节流,字符串需要encode编码
msg = "Hello Socket!"
client_socket.send(msg.encode("utf-8"))
# 接收服务端返回消息
recv_data = client_socket.recv(1024)
print("收到服务端响应:", recv_data.decode("utf-8"))
# 关闭套接字
client_socket.close()
客户端逻辑更直接:先连接,再发送,再接收,最后关闭。这里的 127.0.0.1 是本机回环地址,只能让本机自己访问。
怎么运行和验证结果
- 先在终端运行服务端:
python server.py - 再新开一个终端运行客户端:
python client.py
运行后,可以看到类似输出:
服务端控制台:
服务端启动成功,监听端口:8888
新客户端接入:('127.0.0.1', 51234)
收到客户端消息: Hello Socket!
客户端控制台:
收到服务端响应: 服务端已收到你的消息!
如果你是第一次接触网络通信,这一步很关键。只要这组代码能跑通,就说明你已经把最基础的 Socket 通信链路搭起来了。
这个示例里最容易忽略的几个细节
- Socket 传输的本质是 bytes 字节流,所以字符串发送前必须
encode(),接收后通常要decode()。 127.0.0.1只适合本机测试。如果希望局域网里的其他设备访问,服务端要绑定0.0.0.0,客户端则要填写服务端所在机器的局域网 IP。- 如果端口已经被其他程序占用,
bind()时就可能抛出OSError。 - 服务端代码里对
if not data的判断不能省。TCP 连接断开时,recv()可能返回空字节,这正是识别对端已断开的一个常见信号。
UDP 通信为什么更轻量,代码怎么写
UDP 和 TCP 的最大区别在于,它不需要先建立连接,因此也就没有 listen 和 accept 这一步。写法上会更简洁,收发方式也不同。

UDP 服务端:udp_server.py
import socket
# SOCK_DGRAM 代表UDP
udp_server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_server.bind(("0.0.0.0", 9999))
print("UDP服务端启动,端口9999")
while True:
data, addr = udp_server.recvfrom(1024)
print(f"来自{addr}消息:{data.decode('utf-8')}")
udp_server.sendto("UDP收到!".encode("utf-8"), addr)
UDP 客户端:udp_client.py
import socket
udp_client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_client.sendto("UDP测试消息".encode("utf-8"), ("127.0.0.1", 9999))
data, addr = udp_client.recvfrom(1024)
print("服务端回复:", data.decode("utf-8"))
udp_client.close()
这里有两个很直观的区别:
- 创建 UDP socket 时,要用
socket.SOCK_DGRAM。 - 发送和接收使用的是
sendto()、recvfrom(),因为每个数据报都要显式带上目标地址或返回来源地址。
如果你的需求更看重传输可靠性,TCP 仍然是更稳妥的起点;如果更看重轻量和实时,UDP 才更合适。
初学 Socket 最常见的 5 个坑
- 编码报错或中文乱码
收发时忘记encode()或decode(),是最常见的问题。统一使用utf-8,能省掉很多麻烦。 - 端口占用
程序启动时报错,先看是不是目标端口已经被其他进程占了。最直接的处理方式通常就是换一个端口,或者结束占用进程。 - 客户端连不上服务端
要重点检查三件事:IP 是否写对、防火墙是否拦截、服务端是否绑定了0.0.0.0。局域网访问失败时,这几个原因最常见。 - recv 阻塞导致程序卡住
recv()默认是阻塞的,没有数据时会一直等。TCP 断开后如果返回空字节,代码里就要及时处理并关闭连接。 - 单次 recv 收不完大数据
缓冲区大小有限,像recv(1024)这样的写法只适合演示和小数据收发。真正传大文件或长消息时,通常需要循环接收,直到完整数据都读完。
跑通示例后,可以往哪些方向继续
上面的代码属于最小可运行版本,适合理解基础流程。但它本质上还是一对一、短连接的简单通信。想继续往实战走,可以重点看这几个方向:

- 使用多线程或多进程,同时处理多个客户端连接。
- 学习
select或selectors,理解 IO 多路复用的基本思路。 - 基于 Socket 自己做一个简易聊天室或文件传输工具,把收发逻辑练熟。
- 给消息增加协议头,定义自己的通信数据包格式。
- 继续了解异步网络编程,例如
asyncio socket。 - 需要更完整的网络框架时,再去看 Twisted、gevent 这类第三方方案。
Socket 是很多上层协议和网络框架的基础。把原生 socket 的连接、收发、阻塞、编码这些基本概念先吃透,再回头看 HTTP、WebSocket 或异步框架,理解会扎实得多。







