前言
网络编程是后端开发、爬虫、内网穿透、即时通讯等场景的基础,而Socket就是实现网络通信最核心的接口。很多初学者刚接触网络编程时,会被TCP、UDP、IP、端口等概念搞得一头雾水。本篇从基础概念出发,使用原生Python标准库socket,从零搭建服务端与客户端通信示例,带你快速上手Socket编程。
前置要求:掌握Python基础语法,无需深入网络底层原理。Python内置socket模块,不需要额外
pip安装。
一、什么是Socket
Socket(套接字)可以理解为网络上两个程序通信的端点 。
两台主机想要互相传递数据,一端开启服务监听,另一端发起连接,依靠IP地址+端口唯一标识一个Socket通信通道。
两种最常用通信协议:
- TCP:面向连接、可靠通信,数据不会丢失、顺序不变。通信前必须建立连接(三次握手),文件传输、聊天软件大多使用TCP。
- UDP:无连接、不可靠通信,不用建立连接,发送速度快,适合直播、语音通话、广播场景,可能丢包。
Python socket库同时支持TCP与UDP套接字。
二、TCP通信完整示例(重点)
TCP通信流程:
服务端:创建socket → 绑定IP端口(bind) → 开始监听(listen) → 阻塞等待连接(accept) → 收发数据
客户端:创建socket → 连接服务端(connect) → 收发数据
2.1 TCP服务端代码 server.py
python
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()
2.2 TCP客户端代码 client.py
python
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()
运行测试
- 终端先运行服务端:
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;- 端口不能被其他程序占用,占用会抛出
OSError。
三、UDP通信示例
UDP不需要建立连接,不需要listen和accept,收发更加轻量化。
UDP服务端 udp_server.py
python
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
python
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()
四、常见踩坑总结
- 编码报错:收发忘记encode/decode,中文极易出现乱码,统一使用utf-8;
- 端口占用:修改PORT,或者关闭占用端口的进程;
- 客户端连不上 :防火墙拦截、IP填写错误、服务端未绑定
0.0.0.0; - recv阻塞卡死:TCP连接断开后recv会返回空字节,代码中需要判断;
- 单次recv不能接收全部大数据:缓冲区有限,传输大文件需要循环接收。
五、进阶拓展方向
原生基础Socket仅实现一对一短连接通信,后续可以延伸学习:
- 使用多线程/多进程处理多个客户端并发连接;
- IO多路复用 select / selectors 实现高并发服务;
- 基于Socket实现简易聊天室、文件传输;
- 封装协议头,自定义通信数据包格式;
- 异步网络编程 asyncio socket;
- 第三方框架:Twisted、gevent。
结束语
Socket是网络编程的基石,HTTP、WebSocket底层依然基于Socket封装。熟练掌握原生socket模块,能帮助你理解各类网络框架底层通信逻辑。本篇示例均为最简可运行代码,建议手动敲一遍运行调试,加深理解。