Python Socket库TCP与UDP通信完整实战教程:从客户端到服务端
Socket(套接字)是网络编程的基石,Python内置的socket模块无需安装即可实现TCP和UDP通信。本文从零开始,详细讲解TCP与UDP客户端和服务端的完整实现、高频配置选项、粘包问题解决方案及三个实战案例,帮助你快速掌握Python网络编程。一、Socket对象创建
导入模块后,通过socket.socket(family, type)创建套接字,family指定地址族(通常为socket.AF_INET代表IPv4),type指定协议类型:socket.SOCK_STREAM为TCP,socket.SOCK_DGRAM为UDP。
import socket
# TCP套接字
tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# UDP套接字
udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
二、TCP通信全套API
TCP是面向连接的可靠协议,通信前需建立三次握手。
1. TCP客户端
客户端需依次执行:创建套接字、设置超时(可选)、连接服务器、发送/接收数据、关闭连接。
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5)# 5秒无响应超时
sock.connect(("127.0.0.1", 8080))
sock.send("你好服务端".encode("utf-8"))
data = sock.recv(1024)
print(data.decode("utf-8"))
sock.close()
2. TCP服务端
服务端创建后需绑定IP和端口、监听、等待客户端连接,然后处理收发。注意启用端口复用避免重启时报错。
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# 端口复用
server.bind(("0.0.0.0", 8080))
server.listen(5)
print("服务端已启动,等待连接...")
conn, client_addr = server.accept()
print("客户端地址:", client_addr)
msg = conn.recv(1024)
print("收到:", msg.decode())
conn.send("收到消息".encode("utf-8"))
conn.close()
三、UDP通信全套API
UDP无连接,直接发数据包。核心方法为sendto和recvfrom。
1. UDP客户端(只发数据)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(b"心跳包", ("127.0.0.1", 9999))
sock.close()
2. UDP服务端接收数据
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("0.0.0.0", 9999))
while True:
data, addr = sock.recvfrom(1024)
print(f"来自{addr}: {data.decode()}")
sock.sendto(b"ok", addr)
3. UDP广播设置(局域网设备发现)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.sendto(b"online", ("255.255.255.255", 9999))
四、高频通用配置选项
1. 端口复用:避免服务端重启时提示Address already in use。
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
2. 设置阻塞超时:recv/accept默认永久阻塞,务必加超时。
sock.settimeout(3)
try:
data = sock.recv(1024)
except socket.timeout:
print("接收超时")
3. 关闭Nagle算法:小包立即发送,适合实时性场景。
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True)
4. 获取本机IP:socket.gethostbyname(socket.gethostname())
5. 域名解析为IP:socket.gethostbyname("www.baidu.com")
五、TCP粘包问题及解决方案
TCP是字节流,多次send的数据可能被合并接收。常用方案:固定长度、前置数据长度、使用分隔符。
示例:发送端添加分隔符"|||",接收端按分隔符切割。
# 发送端
sock.send(b"hello|||")
# 接收端按分隔符切割数据
六、实战案例
案例1:TCP端口存活检测
def port_check(host, port, timeout=2):
try:
sock = socket.socket()
sock.settimeout(timeout)
sock.connect((host, port))
sock.close()
return True
except:
return False
案例2:裸Socket发送HTTP请求
sock = socket.socket()
sock.connect(("www.baidu.com", 80))
http_header = b"GET / HTTP/1.1\r\nHost:www.baidu.com\r\nConnection:close\r\n\r\n"
sock.send(http_header)
print(sock.recv(4096).decode("utf-8", errors="ignore"))
sock.close()
七、避坑总结
1. 所有收发数据必须是bytes,字符串需.encode("utf-8")。
2. TCP必须先连接再收发,UDP直接sendto。
3. recv缓冲区合理设置(如1024),太小会读不全。
4. 必须设置超时,避免无限阻塞。
5. 服务端绑定0.0.0.0才能对外网与局域网开放,绑定127.0.0.1仅本机。
6. 短连接收发完毕及时close,避免大量TIME_WAIT占用端口。
掌握以上内容,你已具备Python socket编程的核心能力。如需多线程TCP服务端、asyncio异步socket、自定义TCP分包协议等高级内容,欢迎探讨。
Re: Python Socket库TCP与UDP通信完整实战教程:从客户端到服务端
感谢楼主的详细教程,结构非常清晰,从基础API到粘包问题再到实战案例,对新手很友好。一个小细节补充:TCP客户端示例中用了`send()`,实际生产环境建议用`sendall()`确保完整发送,尤其在传输大文件时更可靠。另外UDP广播示例里目标地址用的是`"255.255.255.255"`,这是受限广播,适合局域网但某些路由器可能会过滤,如果需要更精确可以用子网广播地址(如`"192.168.1.255"`)。总体非常实用,收藏了!Re: Python Socket库TCP与UDP通信完整实战教程:从客户端到服务端
很实用的入门教程,把TCP和UDP的核心流程、常用配置和踩坑点都讲清楚了。对刚接触网络编程的人来说,粘包问题的示例和端口检测的实战案例帮助很大。Re: Python Socket库TCP与UDP通信完整实战教程:从客户端到服务端
感谢分享,非常详实的教程!尤其是粘包那部分,直接给分隔符和固定长度两种思路,很实用。想问下UDP广播用255.255.255.255,在路由器启用了隔离或客户端在不同子网时,是不是需要改用subnet定向广播地址?实际项目里有没有踩过坑?
页:
[1]