socket 是程序与网络之间的底层通信接口,python 通过 socket 模块封装 bsd api,支持 tcp/udp、客户端-服务器交互等;tcp 面向连接可靠传输,udp 无连接轻量适合实时场景;需注意端口复用、连接异常、数据编解码等常见问题。

什么是 socket,为什么需要它
socket 是网络通信的底层接口,可以理解为程序与网络之间的“插槽”。Python 的 socket 模块封装了操作系统提供的 BSD socket API,让我们能用简洁代码实现 TCP/UDP 通信、客户端-服务器交互、跨进程数据传输等。不依赖第三方库,标准库开箱即用,是理解网络编程本质的起点。
TCP 客户端与服务器的最小可运行示例
TCP 是面向连接、可靠传输的协议,适合大多数场景(如 HTTP、SSH)。下面是最简但可直接运行的 echo 服务:服务端接收消息并原样返回,客户端发送一次后退出。
服务端(server.py):
import socket
<p>s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1', 8888))
s.listen(1)
print("Server listening on 127.0.0.1:8888")</p><p>conn, addr = s.accept()
print(f"Connected by {addr}")</p><p>data = conn.recv(1024)
if data:
conn.sendall(data) # 回显
conn.close()
s.close()
客户端(client.py):
立即学习“Python免费学习笔记(深入)”;
import socket
<p>s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 8888))
s.sendall(b'Hello, Server!')
response = s.recv(1024)
print("Received:", response.decode())
s.close()
运行顺序:先启动 server.py,再运行 client.py。注意几点:
- AF_INET 表示 IPv4 地址族;SOCK_STREAM 表示 TCP
- bind() 需指定 IP 和端口,listen() 的参数是最大等待连接数
- recv() 不保证一次收完所有数据,实际项目中需循环读取或按协议解析长度
- sendall() 确保全部数据发出,比 send() 更稳妥
处理多个客户端:引入多线程或 select
上面的服务端只能处理一个连接,用完即关。真实服务需并发响应多个客户端。有两种轻量方案:
1、数据调用该功能使界面与程序分离实施变得更加容易,美工无需任何编程基础即可完成数据调用操作。2、交互设计该功能可以方便的为栏目提供个性化性息功能及交互功能,为产品栏目添加产品颜色尺寸等属性或简单的留言和订单功能无需另外开发模块。3、静态生成触发式静态生成。4、友好URL设置网页路径变得更加友好5、多语言设计1)UTF8国际编码; 2)理论上可以承担一个任意多语言的网站版本。6、缓存机制减轻服务器
-
多线程版(简单直观,适合低并发):每次 accept 后,用
threading.Thread包装处理函数,主线程继续 accept 新连接 -
select 版(单线程高并发,适合学习 I/O 多路复用):用
select.select()监听多个 socket(如监听套接字 + 已连接套接字),有数据到达时才 recv,避免阻塞
例如多线程服务器核心逻辑:
def handle_client(conn, addr):
print(f"Handling {addr}")
while True:
data = conn.recv(1024)
if not data:
break
conn.sendall(data)
conn.close()
<h1>在 accept 后:</h1><p>thread = threading.Thread(target=handle_client, args=(conn, addr))
thread.daemon = True
thread.start()
UDP 通信:无连接、轻量、适合广播和实时场景
UDP 不建连、不重传、不排序,开销小,适用于 DNS 查询、视频流、游戏状态同步等对实时性要求高、可容忍少量丢包的场景。
UDP 服务器(udp_server.py):
import socket
<p>s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('127.0.0.1', 9999))</p><p>while True:
data, addr = s.recvfrom(1024)
print(f"From {addr}: {data.decode()}")
s.sendto(b'Pong!', addr)
UDP 客户端(udp_client.py):
import socket
<p>s = socket.socket(socket.AF_INET, socket.SOCK<em>DGRAM)
s.sendto(b'Ping!', ('127.0.0.1', 9999))
data, </em> = s.recvfrom(1024)
print("Reply:", data.decode())
s.close()
关键区别:
- UDP 使用 SOCK_DGRAM,调用 recvfrom() 和 sendto(),自动携带地址信息
- 无需 connect、listen、accept;服务器持续监听,客户端可随时发包
- 不保证送达,也不保证顺序——应用层需自行处理超时、重发、校验
常见问题与调试建议
初学 socket 编程容易卡在几个地方:
-
Address already in use:端口被占用,可在 bind 前加
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - Connection refused:客户端连不上,检查服务端是否已运行、IP 和端口是否匹配、防火墙是否拦截
-
recv() 阻塞或返回空:TCP 中空数据通常表示对端 close;UDP 中 recvfrom 会一直等,可用
settimeout()控制 - 中文乱码:确保 send 前 encode('utf-8'),recv 后 decode('utf-8')
调试技巧:用 netstat -an | grep 8888(Linux/macOS)或 netstat -ano | findstr :8888(Windows)查看端口占用;用 telnet 127.0.0.1 8888 快速测试 TCP 连通性。










