只要涉及后端服务、爬虫、即时通讯或局域网通信,Socket 基本都是绕不开的入口。很多人第一次学网络编程,容易被 TCP、UDP、IP、端口这些名词劝退;其实先把 Python 里的收发流程跑通,再回头理解概念会顺很多。下面就从最常见的服务端、客户端示例入手,带你快速判断什么时候用 TCP、什么时候用 UDP,以及新手最容易卡住的几个点该怎么排查。
Socket 到底是什么
Socket(套接字)可以把它理解成网络上两个程序通信的端点。一端负责监听请求,另一端主动发起连接,双方通过 IP 地址和端口号找到彼此,从而建立一条通信通道。
刚入门时,最常见的是下面两种协议:
- TCP:面向连接、可靠传输,数据顺序可控,丢包后会处理,适合文件传输、聊天软件这类对完整性要求高的场景。
- UDP:无连接、发送更轻量,不保证一定送达,常见于直播、语音通话、广播等更看重实时性的场景。
Python 标准库已经内置了 socket 模块,不需要额外 pip 安装。只要有 Python 基础语法,就可以直接开始写最基础的网络通信程序。
TCP 通信怎么写:一组完整可运行示例
如果你想先建立稳定的一问一答通信,TCP 是最适合入门的选择。它的流程可以直接记成两条线:

服务端:创建 socket → 绑定地址和端口 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()
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()
怎么运行这组 TCP 示例
- 先在终端启动服务端:
python server.py - 再打开一个新终端运行客户端:
python client.py
正常情况下,你会看到类似输出:
服务端控制台:
服务端启动成功,监听端口:8888
新客户端接入:('127.0.0.1', 51234)
收到客户端消息: Hello Socket!
客户端控制台:
收到服务端响应: 服务端已收到你的消息!
这组代码里有三个入门时特别重要的细节:
- Socket 传输的本质是 bytes 字节流,字符串发送前要
encode(),接收后再decode()。 127.0.0.1只表示本机回环地址。如果要让局域网其他设备连接,服务端继续绑定0.0.0.0,客户端则要改成服务端所在机器的局域网 IP。- 端口如果已经被其他程序占用,执行
bind时就可能抛出OSError。
UDP 通信示例:代码更短,但模型不同
UDP 不需要先建立连接,因此也就不需要 listen 和 accept。如果你只是想快速体验“发一条消息、收一条回复”的过程,UDP 的代码会更直观。

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()
和 TCP 相比,这里最明显的差异是:
- 使用的是
socket.SOCK_DGRAM; - 发送和接收分别通过
sendto()、recvfrom()完成; - 代码里不需要显式建立连接,但也正因为这样,UDP 不保证消息一定到达。
新手最常见的几个坑
把示例跑起来后,真正花时间的通常不是写代码,而是排查这些基础问题:

- 编码报错或乱码:收发两端忘记统一使用
encode()/decode(),中文内容尤其容易出问题,通常统一成utf-8就够了。 - 端口被占用:更换一个
PORT,或者结束占用该端口的进程。 - 客户端连不上服务端:优先检查 IP 是否写错、服务端是否已经启动、防火墙是否拦截,以及服务端是否绑定了
0.0.0.0。 recv阻塞:TCP 连接断开后,recv可能返回空字节,代码里需要像示例那样先判断if not data。- 一次
recv收不完大数据:缓冲区大小有限,处理大文件或长消息时要改成循环接收。
入门之后还能往哪扩展
上面的示例适合帮助你建立基本认识,但在真实项目里,Socket 通常还会继续往这些方向发展:
- 用多线程或多进程同时处理多个客户端连接;
- 使用
select/selectors做 IO 多路复用; - 基于 Socket 自己实现简易聊天室或文件传输工具;
- 在应用层封装协议头,定义自己的消息格式;
- 尝试异步网络编程,例如
asyncio socket; - 继续接触更高层的网络框架,比如 Twisted、gevent。
Socket 是很多网络协议和框架的基础。先把这几段最小可运行代码理解透,后面再看 HTTP、WebSocket 或各种服务框架时,会更容易看明白它们底层到底在做什么。







