68人参与 • 2026-05-14 • Python
在当今的互联网世界中,几乎所有的应用程序都离不开网络通信。无论是你在浏览器中输入网址访问网页,还是手机 app 向服务器提交数据,背后都在运行着复杂的网络协议。对于 python 开发者而言,掌握网络编程是进阶的必经之路。而在众多协议中,tcp/ip 协议族无疑是互联网的基石。
tcp(transmission control protocol,传输控制协议)与 ip(internet protocol,网际协议)通常协同工作。ip 负责将数据包从源头路由到目的地,就像邮局系统负责将信件投递到正确的城市;而 tcp 则负责在 ip 层之上建立可靠的连接,确保数据包按顺序、无差错地到达,就像邮局保证信件不仅送达,而且内容完整、顺序正确。
在 python 中,我们通常使用内置的 socket 模块来直接操作这些底层协议。这就像给了我们一把打开网络世界大门的钥匙。socket(套接字)是网络通信的端点,它抽象了底层的协议细节,让我们能够以“打开连接 -> 读写数据 -> 关闭连接”的简单模式来处理复杂的网络交互。
理解 tcp 通信的核心在于“三次握手”和“面向连接”的特性:
在 python 的世界里,我们不需要手动处理这些底层细节,但理解其原理对于编写高性能、健壮的网络程序至关重要。接下来的章节,我们将通过代码实战,演示如何利用 python 实现一个简单的 tcp 客户端和服务端,完成数据的“提交”(发送)与“读取”(接收)。
要进行通信,首先必须有一方充当服务端(server),负责监听特定的端口,等待客户端的连接。在 python 中,搭建一个基础的 tcp 服务端通常只需要几行代码,但其中蕴含着严谨的逻辑流程。
一个标准的 tcp 服务端执行流程如下:
socket.socket() 创建一个套接字对象。让我们编写一个“回显服务器”(echo server),它会读取客户端发来的消息,并原样返回给客户端。
import socket
def start_server():
# 1. 定义主机和端口
host = '127.0.0.1' # 本机回环地址
port = 65432 # 监听的端口(大于1024,避免系统占用)
# 2. 创建 tcp socket (af_inet 表示 ipv4, sock_stream 表示 tcp)
with socket.socket(socket.af_inet, socket.sock_stream) as s:
# 3. 绑定地址
s.bind((host, port))
print(f"服务端已启动,正在监听 {host}:{port} ...")
# 4. 开始监听,参数表示最大挂起连接数
s.listen()
# 5. 接受连接 (accept 是阻塞的)
conn, addr = s.accept()
with conn:
print(f"已连接客户端地址: {addr}")
while true:
# 6. 读取数据 (每次最多读取 1024 字节)
data = conn.recv(1024)
if not data:
# 如果接收到空数据,说明客户端关闭了连接
print("客户端断开连接")
break
# 打印接收到的消息(注意解码)
print(f"收到消息: {data.decode('utf-8')}")
# 7. 提交响应(回显)
conn.sendall(data)
print("已回显数据")
if __name__ == '__main__':
start_server()
关键点解析:
with 语句:这是 python 的一大特性,它确保了 socket 在使用完毕后能自动关闭,释放端口资源,防止“端口占用”错误。recv(1024):这是“读取”操作的核心。它尝试从内核的接收缓冲区读取最多 1024 字节的数据。如果缓冲区为空,程序会在这里阻塞等待。encode,接收后需要 decode。这个服务端虽然简单,但它完整地展示了 tcp 通信中服务端如何被动地等待并“读取”数据。
有了服务端,我们需要一个客户端来发起连接并“提交”数据。客户端的逻辑相对简单,它不需要绑定端口(操作系统会随机分配一个临时端口),也不需要监听,它的核心任务是:发起连接、发送数据、接收响应。
下面的客户端代码将连接上一章的服务端,并提交一段文本。
import socket
def start_client():
host = '127.0.0.1' # 服务端的 ip
port = 65432 # 服务端的端口
# 1. 创建 socket
with socket.socket(socket.af_inet, socket.sock_stream) as s:
try:
# 2. 连接服务端
s.connect((host, port))
print(f"成功连接到服务器 {host}:{port}")
# 3. 准备并提交数据
message = "hello, tcp/ip world! 这是一次数据提交测试。"
s.sendall(message.encode('utf-8'))
print(f"已提交数据: {message}")
# 4. 读取服务端的响应
data = s.recv(1024)
print(f"收到服务端响应: {data.decode('utf-8')}")
except connectionrefusederror:
print("连接被拒绝,请确保服务端已启动!")
except exception as e:
print(f"发生错误: {e}")
if __name__ == '__main__':
start_client()
实战技巧:
connectionrefusederror 是最常见的错误之一,通常意味着服务端未启动。当你同时运行服务端和客户端代码时,你会看到:
服务端输出:
服务端已启动,正在监听 127.0.0.1:65432 ...
已连接客户端地址: ('127.0.0.1', 5xxxxx)
收到消息: hello, tcp/ip world! 这是一次数据提交测试。
已回显数据
客户端断开连接
客户端输出:
成功连接到服务器 127.0.0.1:65432
已提交数据: hello, tcp/ip world! 这是一次数据提交测试。
收到服务端响应: hello, tcp/ip world! 这是一次数据提交测试。
这标志着你已经成功使用 python 完成了基于 tcp/ip 的基础数据提交与读取。
虽然上述代码在本地运行良好,但直接用于生产环境(如 web 服务器)是不够的。因为标准的 socket 默认是阻塞的。
在服务端的 accept() 和 recv() 调用中,程序会停下来等待,直到有事情发生。如果一个客户端连接了但不发送数据,或者发送很慢,服务器就会一直卡在那,无法处理其他客户端的请求。这被称为“单线程阻塞模型”。
为了解决这个问题,通常有三种主流方案:
多线程/多进程 (threading/multiprocessing):
threading 模块。i/o 多路复用 (i/o multiplexing):
select、poll 或 epoll(linux)机制,让内核同时监控多个 socket,当某个 socket 可读或可写时,再通知程序去处理。select 模块,或者更高级的 selectors 模块。异步 i/o (asynchronous i/o):
asyncio 库(python 3.5+ 推荐)。使用 asyncio 改写上述服务端,逻辑会发生根本性变化:
import asyncio
async def handle_client(reader, writer):
# 读取数据
data = await reader.read(100)
message = data.decode()
addr = writer.get_extra_info('peername')
print(f"收到来自 {addr} 的消息: {message}")
# 写入数据(提交响应)
writer.write(data)
await writer.drain() # 确保数据发送完毕
print("关闭连接")
writer.close()
async def main():
server = await asyncio.start_server(handle_client, '127.0.0.1', 65432)
async with server:
await server.serve_forever()
asyncio.run(main())
这段代码中,await 关键字是核心,它释放了控制权,使得单线程可以并发处理成千上万的连接。
通过本文,我们从最基础的 tcp/ip 协议概念入手,利用 python 原生的 socket 模块,一步步实现了数据的“提交”与“读取”。
我们学到了:
网络编程是充满魅力的领域。掌握了这些底层知识,你不仅能写出更健壮的代码,还能更深刻地理解 http、websocket 等上层协议的工作原理。
以上就是python基于tcp/ip协议实现数据提交与读取的详细内容,更多关于python网络数据通信的资料请关注代码网其它相关文章!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论