您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# Python中套接字编程的示例分析
## 1. 套接字编程基础概念
### 1.1 什么是套接字
套接字(Socket)是计算机网络通信的基本抽象概念,可以看作是两个程序之间进行双向通信的端点。在Python中,套接字编程是通过`socket`模块实现的,它提供了BSD套接字接口的访问方法。
套接字主要有以下特性:
- 通信端点:标识网络中的特定进程
- 支持多种协议族(如IPv4、IPv6)
- 提供不同类型的通信服务(流式、数据报等)
### 1.2 套接字类型
Python中常见的套接字类型包括:
1. **流式套接字(SOCK_STREAM)**
- 面向连接的可靠通信
- 基于TCP协议
- 保证数据顺序和可靠性
2. **数据报套接字(SOCK_DGRAM)**
- 无连接的不可靠通信
- 基于UDP协议
- 不保证数据顺序和可靠性
3. **原始套接字(SOCK_RAW)**
- 允许直接访问底层协议
- 需要特殊权限
- 常用于网络嗅探和自定义协议实现
## 2. Python socket模块详解
### 2.1 核心API方法
```python
import socket
# 创建套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定地址和端口
s.bind(('localhost', 8080))
# 监听连接
s.listen(5)
# 接受连接
conn, addr = s.accept()
# 发送数据
conn.send(b'Hello, client')
# 接收数据
data = conn.recv(1024)
# 关闭连接
conn.close()
方法 | 描述 |
---|---|
socket() |
创建新的套接字 |
bind() |
将套接字绑定到特定地址和端口 |
listen() |
启用服务器接受连接 |
accept() |
接受连接并返回(conn, address) |
connect() |
连接到远程套接字 |
send() |
发送TCP数据 |
recv() |
接收TCP数据 |
sendto() |
发送UDP数据 |
recvfrom() |
接收UDP数据 |
close() |
关闭套接字 |
import socket
def tcp_server():
# 创建TCP套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置地址重用
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定地址和端口
server_socket.bind(('0.0.0.0', 8888))
# 开始监听
server_socket.listen(5)
print("TCP服务器启动,等待客户端连接...")
try:
while True:
# 接受客户端连接
client_socket, client_addr = server_socket.accept()
print(f"客户端 {client_addr} 已连接")
try:
while True:
# 接收数据
data = client_socket.recv(1024)
if not data:
break
print(f"收到来自 {client_addr} 的数据: {data.decode()}")
# 发送响应
response = f"已收到你的消息: {data.decode()}"
client_socket.send(response.encode())
except ConnectionResetError:
print(f"客户端 {client_addr} 异常断开")
finally:
client_socket.close()
except KeyboardInterrupt:
print("服务器关闭")
finally:
server_socket.close()
if __name__ == '__main__':
tcp_server()
import socket
def tcp_client():
# 创建TCP套接字
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
# 连接服务器
client_socket.connect(('localhost', 8888))
while True:
message = input("请输入要发送的消息(输入quit退出): ")
if message.lower() == 'quit':
break
# 发送数据
client_socket.send(message.encode())
# 接收响应
response = client_socket.recv(1024)
print(f"服务器响应: {response.decode()}")
except ConnectionRefusedError:
print("无法连接到服务器")
finally:
client_socket.close()
if __name__ == '__main__':
tcp_client()
三次握手建立连接
数据传输阶段
四次挥手断开连接
import socket
def udp_server():
# 创建UDP套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定地址和端口
server_socket.bind(('0.0.0.0', 8888))
print("UDP服务器启动,等待客户端消息...")
try:
while True:
# 接收数据和客户端地址
data, client_addr = server_socket.recvfrom(1024)
print(f"收到来自 {client_addr} 的数据: {data.decode()}")
# 发送响应
response = f"已收到你的消息: {data.decode()}"
server_socket.sendto(response.encode(), client_addr)
except KeyboardInterrupt:
print("服务器关闭")
finally:
server_socket.close()
if __name__ == '__main__':
udp_server()
import socket
def udp_client():
# 创建UDP套接字
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ('localhost', 8888)
try:
while True:
message = input("请输入要发送的消息(输入quit退出): ")
if message.lower() == 'quit':
break
# 发送数据
client_socket.sendto(message.encode(), server_address)
# 接收响应
response, _ = client_socket.recvfrom(1024)
print(f"服务器响应: {response.decode()}")
finally:
client_socket.close()
if __name__ == '__main__':
udp_client()
无连接特性
不可靠性
效率优势
import socket
def non_blocking_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setblocking(False) # 设置为非阻塞模式
server_socket.bind(('0.0.0.0', 8888))
server_socket.listen(5)
connections = []
try:
while True:
try:
# 非阻塞接受连接
conn, addr = server_socket.accept()
conn.setblocking(False)
connections.append((conn, addr))
print(f"新连接: {addr}")
except BlockingIOError:
pass
# 处理现有连接
for conn, addr in connections[:]:
try:
data = conn.recv(1024)
if data:
print(f"收到 {addr} 的数据: {data.decode()}")
conn.send(b"ACK")
else:
conn.close()
connections.remove((conn, addr))
except BlockingIOError:
continue
finally:
for conn, _ in connections:
conn.close()
server_socket.close()
import socket
import threading
def handle_client(conn, addr):
print(f"新客户端连接: {addr}")
try:
while True:
data = conn.recv(1024)
if not data:
break
print(f"收到来自 {addr} 的消息: {data.decode()}")
conn.send(b"ACK")
except ConnectionResetError:
print(f"客户端 {addr} 异常断开")
finally:
conn.close()
def threaded_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('0.0.0.0', 8888))
server_socket.listen(5)
print("多线程服务器启动...")
try:
while True:
conn, addr = server_socket.accept()
client_thread = threading.Thread(
target=handle_client,
args=(conn, addr)
)
client_thread.start()
finally:
server_socket.close()
if __name__ == '__main__':
threaded_server()
import socket
import select
def select_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('0.0.0.0', 8888))
server_socket.listen(5)
# 可读套接字列表
inputs = [server_socket]
try:
while inputs:
# 使用select监控可读套接字
readable, _, _ = select.select(inputs, [], [])
for s in readable:
if s is server_socket:
# 有新连接
conn, addr = server_socket.accept()
inputs.append(conn)
print(f"新连接: {addr}")
else:
# 有数据到达
data = s.recv(1024)
if data:
print(f"收到数据: {data.decode()}")
s.send(b"ACK")
else:
# 连接关闭
inputs.remove(s)
s.close()
finally:
server_socket.close()
缓冲区溢出
拒绝服务攻击
信息泄露
import ssl
import socket
def ssl_server():
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile="server.crt", keyfile="server.key")
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('0.0.0.0', 8888))
server_socket.listen(5)
print("SSL服务器启动...")
try:
while True:
conn, addr = server_socket.accept()
ssl_conn = context.wrap_socket(conn, server_side=True)
try:
data = ssl_conn.recv(1024)
print(f"收到加密数据: {data.decode()}")
ssl_conn.send(b"Secure ACK")
finally:
ssl_conn.close()
finally:
server_socket.close()
输入验证与过滤
资源管理
# 使用with语句管理套接字
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('localhost', 8888))
s.listen(1)
conn, addr = s.accept()
with conn:
data = conn.recv(1024)
conn.sendall(data)
import socket
from datetime import datetime
def simple_http_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('0.0.0.0', 8080))
server_socket.listen(1)
print("简易HTTP服务器运行在 http://localhost:8080")
try:
while True:
conn, addr = server_socket.accept()
request = conn.recv(1024).decode()
# 解析请求行
request_line = request.split('\r\n')[0]
method, path, _ = request_line.split()
# 构建响应
response_body = f"""
<html>
<head><title>Python HTTP服务器</title></head>
<body>
<h1>欢迎使用Python HTTP服务器</h1>
<p>当前时间: {datetime.now()}</p>
<p>请求方法: {method}</p>
<p>请求路径: {path}</p>
</body>
</html>
"""
response = (
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
f"Content-Length: {len(response_body)}\r\n"
"\r\n"
f"{response_body}"
)
conn.send(response.encode())
conn.close()
finally:
server_socket.close()
import socket
import threading
import time
clients = {}
lock = threading.Lock()
def broadcast(message, sender=None):
with lock:
for addr, conn in clients.items():
if conn != sender:
try:
conn.send(message.encode())
except:
del clients[addr]
def handle_client(conn, addr):
with lock:
clients[addr] = conn
try:
conn.send("欢迎加入聊天室!".encode())
while True:
data = conn.recv(1024).decode()
if not data:
break
message = f"[{addr[0]}:{addr[1]}] {data}"
print(message)
broadcast(message, conn)
except ConnectionResetError:
print(f"{addr} 断开连接")
finally:
with lock:
if addr in clients:
del clients[addr]
conn.close()
def chat_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('0.0.0.0', 8888))
server_socket.listen(5)
print("聊天服务器启动...")
try:
while True:
conn, addr = server_socket.accept()
print(f"新用户加入: {addr}")
thread = threading.Thread(target=handle_client, args=(conn, addr))
thread.start()
finally:
server_socket.close()
if __name__ == '__main__':
chat_server()
缓冲区大小调整
减少系统调用
连接复用
使用telnet测试
telnet localhost 8888
网络抓包分析
日志记录
import logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def logged_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
server_socket.bind(('0.0.0.0', 8888))
server_socket.listen(5)
logging.info("服务器启动成功")
while True:
try:
conn, addr = server_socket.accept()
logging.info(f"新连接: {addr}")
data = conn.recv(1024)
logging.debug(f"收到数据: {data}")
conn.send(b"ACK")
conn.close()
except Exception as e:
logging.error(f"处理连接时出错: {e}")
finally:
server_socket.close()
logging.info("服务器关闭")
socket
模块提供套接字编程接口异步I/O编程
高级协议实现
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。