Python网络套接字编程入门
Python 内置了强大的 socket 模块,用于实现底层网络通信。该模块支持多种协议和通信模式,是构建客户端与服务器应用的基础。
一、套接字类型与创建方式
通过 socket(family, type, protocol) 函数创建套接字,其中:
family定义地址族:如AF_INET(IPv4)、AF_INET6(IPv6)或AF_UNIX(本地进程间通信)。type指定通信类型:如SOCK_STREAM(TCP 流式传输)、SOCK_DGRAM(UDP 数据报)、SOCK_RAW(原始套接字,可操作底层协议头)。
示例:
# 创建 TCP 套接字
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 创建 UDP 套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
二、核心方法说明
不同类型的套接字使用不同的通信方式:
| 方法 | 用途 |
|---|---|
bind((host, port)) | 绑定本地地址和端口,仅服务端使用。 |
listen(backlog) | 启用监听,等待客户端连接请求。 |
accept() | 接收一个连接,返回新套接字和客户端地址。 |
connect(address) | 主动连接远程服务端,客户端调用。 |
recv(bufsize) | 接收数据(通常为字符串),适用于 TCP。 |
send(data) | 发送数据到已连接的对端。 |
sendall(data) | 确保所有数据被发送,失败时抛异常。 |
recvfrom(bufsize) | 接收来自 UDP 的数据及发送方地址。 |
sendto(data, address) | 向指定地址发送 UDP 数据包。 |
close() | 关闭套接字资源。 |
settimeout(seconds) | 设置操作超时时间,避免无限阻塞。 |
getsockname() | 获取本机绑定的地址信息。 |
getpeername() | 获取远程连接的地址。 |
三、典型通信流程
TCP 服务端逻辑:
- 创建套接字并绑定地址与端口。
- 启动监听。
- 循环接受连接请求。
- 读取客户端消息并处理后回传结果。
- 关闭连接。
TCP 客户端流程:
- 创建套接字。
- 连接目标服务器。
- 发送指令并接收响应。
- 结束通信并关闭连接。
四、实际代码示例
服务端(命令执行响应):
import socket
import subprocess
HOST = '127.0.0.1'
PORT = 8888
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_sock.bind((HOST, PORT))
server_sock.listen(5)
print("等待连接...")
while True:
client_conn, client_addr = server_sock.accept()
print(f"已连接: {client_addr}")
while True:
data = client_conn.recv(1024).decode('utf-8').strip()
if not data:
break
try:
result = subprocess.run(data, shell=True, capture_output=True, text=True)
response = result.stdout or result.stderr or "Done."
except Exception as e:
response = str(e)
client_conn.sendall(response.encode('utf-8'))
client_conn.close()
客户端(交互式命令行工具):
import socket
HOST = '127.0.0.1'
PORT = 8888
client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_sock.connect((HOST, PORT))
print("输入命令(输入 'quit' 退出):")
while True:
cmd = input("> ").strip()
if cmd.lower() == 'quit':
break
client_sock.sendall(cmd.encode('utf-8'))
reply = client_sock.recv(1024).decode('utf-8')
print(reply)
client_sock.close()
注意:在实际开发中,建议使用 subprocess 替代过时的 commands 模块,并对输入进行安全校验以防止注入攻击。