网络编程是现代软件开发的核心技术之一,它允许不同设备上的程序通过网络进行通信和数据交换。本文将深入探讨网络编程的基础知识,包括软件架构设计模式、网络通信三要素、TCP 与 UDP 协议的特点,以及 Python 中 Socket 编程的实现方法。
C/S 架构是最经典的网络应用架构,由客户端(Client)和服务器(Server)两部分组成:
优点:
缺点:
B/S 架构是 C/S 架构的一种特殊形式,它使用 Web 浏览器作为客户端:
优点:
缺点:
P2P 架构中,每个节点既是客户端又是服务器,节点之间直接通信:
优点:
缺点:
IP 地址是网络中设备的唯一标识,分为 IPv4 和 IPv6 两种:
xxx.xxx.xxx.xxx
,如192.168.1.1
2001:0db8:85a3:0000:0000:8a2e:0370:7334
端口号用于标识同一台设备上的不同应用程序,范围从 0 到 65535:
传输协议定义了数据传输的规则和格式,常见的有 TCP 和 UDP:
特性 | TCP | UDP |
---|---|---|
连接方式 | 面向连接 | 无连接 |
可靠性 | 可靠(保证数据顺序和完整性) | 不可靠(不保证数据到达) |
传输效率 | 较低(需要建立连接和确认机制) | 较高(无需连接和确认) |
传输单位 | 字节流 | 数据报 |
应用场景 | 文件传输、邮件、网页浏览 | 实时音视频、游戏、DNS |
TCP 协议通过以下机制确保数据传输的可靠性:
三次握手(Three-way Handshake):建立连接
四次挥手(Four-way Handshake):关闭连接
滑动窗口(Sliding Window):流量控制
重传机制:丢失数据包的重传
拥塞控制:避免网络拥塞
UDP 协议是一种简单的传输协议,主要特点:
Socket(套接字)是网络编程的基础接口,它提供了不同主机间进程通信的机制。在 Python 中,通过socket
模块可以方便地实现 Socket 编程。
socket.SOCK_STREAM
socket.SOCK_DGRAM
socket.socket(family, type)
socket.bind(address)
socket.listen(backlog)
socket.accept()
socket.connect(address)
socket.send(bytes)
或socket.sendto(bytes, address)
socket.recv(bufsize)
或socket.recvfrom(bufsize)
socket.close()
import socket
# 创建TCP Socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定地址和端口
server_address = ('localhost', 8888)
server_socket.bind(server_address)
# 监听连接
server_socket.listen(1)
print(f"服务器启动,监听地址:{server_address}")
while True:
# 接受客户端连接
print("等待客户端连接...")
client_socket, client_address = server_socket.accept()
print(f"客户端已连接:{client_address}")
try:
# 接收客户端数据
data = client_socket.recv(1024)
print(f"收到数据:{data.decode('utf-8')}")
# 发送响应
response = f"服务器已收到:{data.decode('utf-8')}"
client_socket.sendall(response.encode('utf-8'))
finally:
# 关闭客户端连接
client_socket.close()
import socket
# 创建TCP Socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务器
server_address = ('localhost', 8888)
print(f"连接服务器:{server_address}")
client_socket.connect(server_address)
try:
# 发送数据
message = "Hello, 服务器!"
print(f"发送数据:{message}")
client_socket.sendall(message.encode('utf-8'))
# 接收响应
data = client_socket.recv(1024)
print(f"收到响应:{data.decode('utf-8')}")
finally:
# 关闭连接
client_socket.close()
import socket
# 创建UDP Socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定地址和端口
server_address = ('localhost', 9999)
server_socket.bind(server_address)
print(f"UDP服务器启动,监听地址:{server_address}")
while True:
# 接收数据
print("等待数据...")
data, client_address = server_socket.recvfrom(1024)
print(f"收到来自{client_address}的数据:{data.decode('utf-8')}")
# 发送响应
response = f"UDP服务器已收到:{data.decode('utf-8')}"
server_socket.sendto(response.encode('utf-8'), client_address)
import socket
# 创建UDP Socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 服务器地址和端口
server_address = ('localhost', 9999)
try:
# 发送数据
message = "Hello, UDP服务器!"
print(f"发送数据:{message}")
client_socket.sendto(message.encode('utf-8'), server_address)
# 接收响应
data, server = client_socket.recvfrom(1024)
print(f"收到来自{server}的响应:{data.decode('utf-8')}")
finally:
# 关闭连接
client_socket.close()
import socket
import threading
def handle_client(client_socket, client_address):
try:
print(f"新客户端连接:{client_address}")
while True:
# 接收客户端数据
data = client_socket.recv(1024)
if not data:
break
print(f"收到{client_address}的数据:{data.decode('utf-8')}")
# 发送响应
response = f"服务器已收到:{data.decode('utf-8')}"
client_socket.sendall(response.encode('utf-8'))
finally:
# 关闭客户端连接
client_socket.close()
print(f"客户端{client_address}已断开连接")
# 创建TCP Socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定地址和端口
server_address = ('localhost', 7777)
server_socket.bind(server_address)
# 监听连接
server_socket.listen(5)
print(f"多线程TCP服务器启动,监听地址:{server_address}")
while True:
# 接受客户端连接
client_socket, client_address = server_socket.accept()
# 创建线程处理客户端请求
client_thread = threading.Thread(
target=handle_client,
args=(client_socket, client_address)
)
client_thread.daemon = True
client_thread.start()
import socket
import select
# 创建TCP Socket并设置为非阻塞模式
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setblocking(0)
# 绑定地址和端口
server_address = ('localhost', 6666)
server_socket.bind(server_address)
# 监听连接
server_socket.listen(5)
print(f"非阻塞TCP服务器启动,监听地址:{server_address}")
# 创建select对象,监视服务器socket和标准输入
inputs = [server_socket]
outputs = []
while True:
# 使用select监听所有socket
readable, writable, exceptional = select.select(inputs, outputs, inputs)
# 处理可读的socket
for s in readable:
if s is server_socket:
# 有新的连接请求
client_socket, client_address = server_socket.accept()
print(f"新客户端连接:{client_address}")
client_socket.setblocking(0)
inputs.append(client_socket)
else:
# 有数据可读
data = s.recv(1024)
if data:
print(f"收到数据:{data.decode('utf-8')}")
if s not in outputs:
outputs.append(s)
else:
# 客户端关闭连接
print(f"客户端断开连接")
if s in outputs:
outputs.remove(s)
inputs.remove(s)
s.close()
# 处理可写的socket
for s in writable:
response = f"服务器已收到消息"
s.sendall(response.encode('utf-8'))
outputs.remove(s)
# 处理异常情况
for s in exceptional:
print(f"处理异常情况,关闭socket")
inputs.remove(s)
if s in outputs:
outputs.remove(s)
s.close()
import socket
def create_tcp_socket():
try:
# 创建TCP Socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置超时时间
s.settimeout(10)
return s
except socket.error as e:
print(f"创建Socket失败:{e}")
return None
def connect_to_server(s, host, port):
try:
# 连接服务器
s.connect((host, port))
print(f"成功连接到服务器:{host}:{port}")
return True
except socket.gaierror as e:
print(f"地址解析失败:{e}")
except socket.error as e:
print(f"连接失败:{e}")
return False
def send_and_receive(s, message):
try:
# 发送数据
s.sendall(message.encode('utf-8'))
# 接收响应
data = s.recv(1024)
print(f"收到响应:{data.decode('utf-8')}")
return data
except socket.timeout as e:
print(f"操作超时:{e}")
except socket.error as e:
print(f"通信错误:{e}")
return None
# 使用示例
if __name__ == "__main__":
s = create_tcp_socket()
if s and connect_to_server(s, 'localhost', 8888):
send_and_receive(s, "Hello, 服务器!")
s.close()
import socket
# 使用with语句自动管理Socket资源
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
# 设置选项,允许地址重用
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定地址和端口
server_address = ('localhost', 8888)
s.bind(server_address)
# 监听连接
s.listen(1)
print(f"服务器启动,监听地址:{server_address}")
# 接受客户端连接
client_socket, client_address = s.accept()
with client_socket:
print(f"客户端已连接:{client_address}")
# 接收数据
data = client_socket.recv(1024)
print(f"收到数据:{data.decode('utf-8')}")
# 发送响应
response = f"服务器已收到:{data.decode('utf-8')}"
client_socket.sendall(response.encode('utf-8'))
本文全面介绍了 Python 网络编程的基础知识,包括:
通过掌握这些知识,可以开发出各种类型的网络应用,包括简单的客户端 / 服务器程序、实时通信系统、分布式应用等。网络编程是一个广阔而深入的领域,本文只是一个起点,建议进一步学习高级网络编程技术,如异步 I/O、WebSocket、RESTful API 等,以满足更复杂的应用需求。