一文详解Python中socket库的完整使用教程
作者:detayun
Socket 又称套接字,是应用程序与网络传输层之间的接口,所有网络通信都基于 Socket,本文详细介绍了Python的socket模块,涵盖TCP和UDP协议的基本概念、常用API方法、高频配置选项及常见问题,有需要的可以了解下
一、socket 简介
Socket 又称套接字,是应用程序与网络传输层之间的接口,所有网络通信都基于 Socket。
Python 内置 socket 模块,无需额外安装,可以直接完成 TCP、UDP 通信。
网络两大传输协议:
- TCP(SOCK_STREAM):面向连接、可靠、三次握手,不会丢包。
- UDP(SOCK_DGRAM):无连接、不可靠,直接发送数据包,速度更快。
导入模块:
import socket
二、socket 对象创建
语法
socket.socket(family, type)
family=socket.AF_INET:IPv4(最常用)type=socket.SOCK_STREAM:TCPtype=socket.SOCK_DGRAM:UDP
示例:
# 创建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 客户端常用方法
| 方法 | 作用 |
|---|---|
connect((host, port)) | 和服务端建立TCP连接 |
send(bytes) | 发送字节数据 |
recv(buffer_size) | 接收数据,返回bytes |
settimeout(n) | 设置阻塞超时时间 |
close() | 关闭套接字 |
完整客户端代码
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5) # 5秒无响应则超时
# 建立连接
sock.connect(("127.0.0.1", 8080))
# 发送数据,只能发送bytes
sock.send("你好服务端".encode("utf-8"))
# 接收数据,最多读取1024字节
data = sock.recv(1024)
print(data.decode("utf-8"))
sock.close()
2. TCP 服务端常用方法
| 方法 | 作用 |
|---|---|
bind((ip, port)) | 绑定本机IP与端口 |
listen(n) | 开启监听,n为等待队列长度 |
accept() | 阻塞等待客户端接入,返回(conn, address) |
完整服务端代码
import socket
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 不需要建立连接,没有 connect(可选),核心方法只有两个:
| 方法 | 作用 |
|---|---|
sendto(data, (ip, port)) | 发送数据并指定目标地址 |
recvfrom(buffer) | 接收数据,同时获取发送方地址 |
1. UDP客户端(只发数据)
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 发送UDP数据包
sock.sendto(b"心跳包", ("127.0.0.1", 9999))
sock.close()
2. UDP服务端接收数据
import socket
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))
三、socket 高频通用配置选项
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是字节流,没有数据包边界,多次发送的数据会粘在一起。
解决方案:
- 固定每条消息长度;
- 先发送数据长度,再发送正文;
- 使用换行符、特殊字符做分隔。
简单分隔示例:
# 发送端 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请求(不使用requests)
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()
六、核心方法汇总表
TCP专用
- connect()
- listen()
- bind()
- accept()
- send()
- recv()
UDP专用
- sendto()
- recvfrom()
公共方法
- settimeout()
- setsockopt()
- close()
七、避坑总结
- 所有收发数据必须是
bytes,字符串必须.encode("utf-8"); - TCP必须先连接再收发,UDP直接发包;
- recv缓冲区要合理设置,太小会读不全数据;
- 一定要设置超时,避免无限阻塞;
- 服务端绑定
0.0.0.0才能对外网与局域网开放;绑定127.0.0.1仅本机访问; - 短连接收发完毕及时close,避免大量TIME_WAIT占用端口。
如果你需要,我可以继续写:
- 多线程TCP服务端
- asyncio异步socket并发探测
- 自定义TCP分包协议解决粘包完整版代码。
到此这篇关于一文详解Python中socket库的完整使用教程的文章就介绍到这了,更多相关Python socket库内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
