Python Socket编程中TCP与UDP的核心差异在于:TCP是面向连接、可靠的协议,适用于文件传输等需数据完整性的场景;UDP无连接、速度快,适合实时音视频、游戏等对延迟敏感的应用。选择依据是对可靠性与速度的需求权衡。

使用Python进行网络编程,核心在于其内置的
socket
Python的
socket
服务器端代码示例:
import socket
import threading # 后面会提到多线程,这里先引入
HOST = '127.0.0.1' # 服务器监听的IP地址
PORT = 65432 # 服务器监听的端口
def handle_client(conn, addr):
"""处理单个客户端连接的函数"""
print(f"Connected by {addr}")
try:
while True:
data = conn.recv(1024) # 接收客户端数据,最大1024字节
if not data: # 如果没有数据,说明客户端断开连接
print(f"Client {addr} disconnected.")
break
message = data.decode('utf-8')
print(f"Received from {addr}: {message}")
# 回复客户端
response = f"Server received: {message}"
conn.sendall(response.encode('utf-8'))
except ConnectionResetError:
print(f"Client {addr} forcibly closed the connection.")
except Exception as e:
print(f"Error handling client {addr}: {e}")
finally:
conn.close() # 关闭客户端连接
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT)) # 绑定IP地址和端口
s.listen() # 开始监听,等待客户端连接
print(f"Server listening on {HOST}:{PORT}")
while True:
conn, addr = s.accept() # 接受新的客户端连接
# 为每个新连接创建一个线程来处理,避免阻塞主进程
client_thread = threading.Thread(target=handle_client, args=(conn, addr))
client_thread.start()客户端代码示例:
立即学习“Python免费学习笔记(深入)”;
import socket
HOST = '127.0.0.1' # 服务器的IP地址
PORT = 65432 # 服务器的端口
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
try:
s.connect((HOST, PORT)) # 连接到服务器
print(f"Connected to {HOST}:{PORT}")
message_to_send = "Hello, server! This is client."
s.sendall(message_to_send.encode('utf-8')) # 发送数据
data = s.recv(1024) # 接收服务器的回复
print(f"Received from server: {data.decode('utf-8')}")
except ConnectionRefusedError:
print("Connection refused. Is the server running?")
except Exception as e:
print(f"An error occurred: {e}")
finally:
print("Client closing connection.")
# s.close() # with 语句块结束时会自动关闭在这些例子中,
socket.AF_INET
socket.SOCK_STREAM
bind()
listen()
accept()
accept()
conn
addr
connect()
encode()
decode()
在Python的Socket编程中,我们通常会选择TCP(传输控制协议)或UDP(用户数据报协议)。这两种协议各有优劣,选择哪一个往往取决于你的应用场景对数据可靠性和传输速度的需求。
TCP (Transmission Control Protocol) TCP是一种面向连接的协议。这意味着在数据传输之前,客户端和服务器之间必须先建立一个可靠的连接。它提供:
何时选择TCP? 我个人在开发需要高度数据完整性的应用时,比如文件传输、网页浏览(HTTP)、电子邮件(SMTP/POP3/IMAP)或数据库连接时,总是优先考虑TCP。它的可靠性省去了很多手动处理数据丢失和乱序的麻烦,虽然会带来一些额外的开销和延迟,但这种“省心”的特性对于大多数业务应用来说是值得的。
在Python中,创建TCP Socket使用
socket.socket(socket.AF_INET, socket.SOCK_STREAM)
UDP (User Datagram Protocol) UDP是一种无连接的协议。它不保证数据的可靠传输,也不保证数据包的顺序。每个UDP数据报都是一个独立的单元,发送后就“不管不顾”了。
何时选择UDP? 对于那些对实时性要求极高,但可以容忍少量数据丢失的应用,UDP是更好的选择。比如在线游戏、实时音视频流(VoIP)、DNS查询等。在这种场景下,如果一个数据包丢失了,重传它反而会增加延迟,不如直接发送下一个数据包,让应用层去处理可能的“瑕疵”。在我看来,如果你需要自己实现复杂的可靠性机制,或者对延迟有极致要求,才会考虑UDP。
在Python中,创建UDP Socket使用
socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sendto()
recvfrom()
总结来说,TCP是“严谨的信使”,确保每一封信都准确无误、按时送达;UDP则是“快速的广播员”,信息发出去就不管了,谁收到算谁的,但速度绝对快。根据你对“信息”的重视程度,做出合适的选择。
在Python Socket编程中,网络环境的复杂性和不可预测性意味着错误和异常是常态。不恰当的错误处理轻则导致程序崩溃,重则引发数据丢失或安全问题。我的经验是,预见并妥善处理这些异常,是构建健壮网络应用的关键。
以下是一些常见的Socket错误和它们的处理策略:
ConnectionRefusedError
connect()
try...except ConnectionRefusedError:
ConnectionResetError
recv()
send()
BrokenPipeError
ConnectionResetError
send()
ConnectionResetError
send()
TimeoutError
connect()
recv()
send()
accept()
socket.settimeout(seconds)
try...except TimeoutError:
BlockingIOError
socket.setblocking(False)
recv()
select
selectors
asyncio
OSError
socket.error
OSError
Address already in use
OSError
通用处理策略:
try...except
try
except
finally
finally
with socket.socket(...) as s:
socket.shutdown(socket.SHUT_RDWR)
记住,网络是不可靠的。与其期望一切顺利,不如假设一切都会出错,并为每一种可能的情况做好准备。这虽然增加了代码的复杂度,但大大提升了程序的健壮性和用户体验。
一个基本的Python Socket服务器,如果不做特殊处理,一次只能处理一个客户端连接。当它在
conn.recv()
conn.send()
有几种主流的方法可以解决这个问题,每种方法都有其适用场景和权衡:
多线程(Threading)
s.accept()
我的示例代码中已经包含了多线程的简单实现,即在
s.accept()
threading.Thread(target=handle_client, args=(conn, addr)).start()
多进程(Multiprocessing)
实现上,将
threading.Thread
multiprocessing.Process
异步I/O(Asynchronous I/O)
recv()
asyncio
async
await
一个
asyncio
import asyncio
async def handle_client_async(reader, writer):
addr = writer.get_extra_info('peername')
print(f"Connected by {addr}")
try:
while True:
data = await reader.read(1024) # 异步读取
if not data:
print(f"Client {addr} disconnected.")
break
message = data.decode('utf-8')
print(f"Received from {addr}: {message}")
response = f"Server received: {message}"
writer.write(response.encode('utf-8')) # 异步写入
await writer.drain() # 确保数据发送完成
except Exception as e:
print(f"Error handling client {addr}: {e}")
finally:
writer.close()
await writer.wait_closed() # 等待写入器关闭
async def main_async():
server = await asyncio.start_server(
handle_client_async, '127.0.0.1', 65432
)
addrs = ', '.join(str(sock.getsockname()) for sock in server.sockets)
print(f"Serving on {addrs}")
async with server:
await server.serve_forever()
# if __name__ == '__main__':
# asyncio.run(main_async())选择哪种并发模型,没有绝对的答案,需要根据项目的具体需求、团队的技术栈以及预期的负载来决定。对于初学者,多线程是一个不错的起点,能够快速理解并发的机制。而对于追求极致性能和扩展性的场景,
asyncio
以上就是如何用Python进行网络编程(Socket)?的详细内容,更多请关注php中文网其它相关文章!
编程怎么学习?编程怎么入门?编程在哪学?编程怎么学才快?不用担心,这里为大家提供了编程速学教程(入门课程),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号