新手吃透 HTTP 与 WebSocket:跑通这八段 Python 代码,秒懂网络通信原理
你每天打开浏览器查资料、用手机刷朋友圈、在电商平台下单——所有这些操作背后,都离不开网络通信协议。其中出场频率最高的两位选手,就是 HTTP 和 WebSocket。
很多初学者把这两个概念混为一谈,或者只知其名不知其用。其实它们的关系并不复杂:HTTP 是“一问一答”的短信式通信,而 WebSocket 是“随时可聊”的电话式通信。
为了让你从“知道”变成“会用”,我们准备了一套循序渐进的实战方案——八段可直接运行的 Python 代码。从零搭建 HTTP 服务端和客户端,再搭建 WebSocket 双向通信,最后实现一个简易广播聊天室。跑完这些代码,你不仅能区分两种协议,还能理解它们各自适合什么场景。

准备工作:安装必需的 Python 库
开始编码之前,请确保你的 Python 环境(3.7 及以上版本)已经安装了以下三个库。在终端中执行:
pip install flask requests websockets
这三个库各有分工:flask 用于搭建 HTTP 服务器,requests 用于发起 HTTP 客户端请求,websockets 用于 WebSocket 的服务器和客户端通信。
第一部分:HTTP 协议——亲手实现“请求-响应”模型
HTTP(超文本传输协议)是 Web 世界的基石。它的工作模式非常直接:客户端(比如浏览器)向服务器发送一个请求,服务器处理之后返回一个响应,然后连接就释放了。下一次请求又是全新的连接。
这种模式称为“无状态短连接”。优点是简单、资源占用少;缺点是服务器无法主动向客户端推送信息,必须等客户端来“问”。
我们用四段代码来完整还原 HTTP 的通信过程。
代码一:HTTP 服务端(基于 Flask)
创建一个文件 http_server.py,写入以下代码:
from flask import Flask, request app = Flask(__name__) @app.route('/greet', methods=['GET']) def greet(): user = request.args.get('user', '朋友') return f"HTTP 服务端说:{user},你好!" if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)运行此文件(python http_server.py),服务端会在 5000 端口监听。它暴露了一个 /greet 路径,接收 GET 请求并返回带用户名的问候。
代码二:HTTP 客户端(使用 requests)
创建 http_client.py:
import requests resp = requests.get( 'http://localhost:5000/greet', params={'user': '小华'} ) print("客户端收到的响应:", resp.text)运行客户端,你会看到输出:“HTTP 服务端说:小华,你好!” 这就完成了一次典型的 HTTP 请求-响应往返。
代码三:HTTP POST 请求示例
除了 GET(通常用于获取资源),POST(用于提交数据)也是常用的方法。这里我们调用一个公开的测试接口 httpbin.org/post,它会把收到的请求体原样返回:
创建 http_post_demo.py:
import requests payload = {'title': '测试文章', 'author': '小李'} resp = requests.post('https://httpbin.org/post', json=payload) print("HTTP 状态码:", resp.status_code) print("服务器回显的数据:", resp.json()['json'])运行后,你会看到服务器将你发送的 JSON 数据原封不动地回传。这验证了 POST 请求能够承载消息体,而 GET 通常只携带 URL 参数。
代码四:纯标准库实现的 HTTP 服务端
如果不依赖 Flask,Python 内置的 http.server 模块也能搭建一个基本的 HTTP 服务。创建 http_stdlib_server.py:
from http.server import HTTPServer, BaseHTTPRequestHandler class CustomHandler(BaseHTTPRequestHandler): def do_GET(self): self.send_response(200) self.send_header('Content-Type', 'text/plain; charset=utf-8') self.end_headers() self.wfile.write("欢迎访问内置 HTTP 服务器".encode('utf-8')) if __name__ == '__main__': server = HTTPServer(('localhost', 8000), CustomHandler) print("服务已启动,访问 http://localhost:8000") server.serve_forever()运行后,在浏览器访问 http://localhost:8000 就能看到返回的文字。这个例子能帮助你理解 HTTP 响应的底层构造——状态码、响应头和响应体。
以上四段代码完整覆盖了 HTTP 的客户端、服务端、GET 和 POST 操作。你可以清楚地看到:每一次通信都由客户端主动发起,服务器被动应答,结束后连接即断开。
第二部分:WebSocket 协议——构建“双向实时”通道
当我们需要实时推送消息(比如聊天、股票行情、在线协作)时,HTTP 的“一问一答”模式就显得力不从心了。因为客户端不知道什么时候该“问”,服务器也不能主动“说”。
WebSocket 的出现就是为了解决这个问题。它通过一次 HTTP 握手建立连接,随后将协议升级为 WebSocket,保持一条长久的 TCP 连接。在这条连接上,客户端和服务器都可以随时主动发送消息,无需等待对方请求。
下面我们用四段代码来实战 WebSocket 的全部核心功能。
代码五:WebSocket 服务端——回声服务器
创建 ws_echo_server.py:
import asyncio from websockets import serve async def echo_handler(websocket): async for message in websocket: await websocket.send(f"Echo: {message}") async def main(): async with serve(echo_handler, 'localhost', 8765): await asyncio.Future() # 持续运行 asyncio.run(main())该服务监听在 ws://localhost:8765。任何客户端发送来的消息,它都会加上 “Echo: ” 前缀后返回。
代码六:WebSocket 客户端(同步方式)
创建 ws_sync_client.py:
from websockets.sync.client import connect with connect('ws://localhost:8765') as websocket: websocket.send('第一次 WebSocket 消息') reply = websocket.recv() print(f'同步客户端收到:{reply}')运行前请确保服务端(代码五)已经启动。客户端会发送一条消息并立即打印回声。
代码七:WebSocket 客户端(异步方式)
异步编程是 WebSocket 的常用模式,尤其适合高并发场景。创建 ws_async_client.py:
import asyncio from websockets import connect async def main(): async with connect('ws://localhost:8765') as websocket: await websocket.send('异步消息测试') response = await websocket.recv() print(f'异步客户端收到:{response}') asyncio.run(main())异步版与同步版功能相同,但使用了 asyncio 事件循环,为后续构建复杂应用打下基础。
代码八:广播式 WebSocket 服务端——简易聊天室
最后一个示例,我们实现一个能够“广播”消息的服务端。所有连接到该服务的客户端,都能收到其他客户端发送的消息。
创建 ws_broadcast_server.py:
import asyncio from websockets import serve # 存放所有已连接的客户端 clients = set() async def broadcast_handler(websocket): # 将新客户端加入集合 clients.add(websocket) try: async for message in websocket: # 将消息转发给除发送者外的所有客户端 for client in clients: if client is not websocket: await client.send(message) finally: # 客户端断开时移除 clients.remove(websocket) async def main(): async with serve(broadcast_handler, 'localhost', 8765): await asyncio.Future() asyncio.run(main())
启动该服务后,你可以同时打开多个客户端(例如运行多次代码六或代码七),任意一个客户端发送消息,其他客户端都会收到。这正好是实时聊天室的核心逻辑。
HTTP 与 WebSocket 的适用场景对比
跑完这八段代码,两种协议的差异已经不言自明。我们可以用一个表格来总结它们的关键区别:
| 比较项目 | HTTP | WebSocket |
|---|---|---|
| 通信方向 | 单向:客户端请求,服务端响应 | 双向:任一方均可主动发送 |
| 连接持久性 | 短连接,每次请求重建 | 长连接,握手后持续保持 |
| 服务器推送能力 | 不支持(需长轮询等变通) | 原生支持,可实时推送 |
| 协议头开销 | 每次携带较大 HTTP 头 | 握手后数据帧极小,开销低 |
| 典型应用 | 网页加载、REST API、文件上传 | 在线聊天、游戏、行情推送、协同编辑 |
选择哪一种协议,完全取决于业务对“实时性”和“交互频次”的要求。如果只需要偶尔获取数据,HTTP 足够且稳定;如果需要持续双向交互,WebSocket 是更合适的技术方案。
常见疑问与注意事项
问:WebSocket 的握手阶段用的是什么协议?
答:握手阶段使用的是 HTTP 协议(通常是 HTTP/1.1)。客户端发送一个特殊的 Upgrade 请求,服务端同意后,连接升级为 WebSocket。所以 WebSocket 是“基于 HTTP 启动,但升级后独立”的协议。
问:WebSocket 能否跨域通信?
答:可以,但服务端需要正确处理跨域策略。在 WebSocket 握手阶段可以通过 Origin 头进行校验,服务端可以通过设置响应头允许特定来源。
问:生产环境中应该选择哪种库?
答:本文选用的 websockets 库轻量且适用于异步场景;如果是大型项目,也可考虑 Socket.IO(提供更多降级方案)或 Django Channels。HTTP 方面,Flask 适合快速开发,FastAPI 则提供更强的异步性能。
问:断线重连如何处理?
答:WebSocket 本身提供了关闭帧(Close Frame),客户端可以监听关闭事件并在断线后尝试重新连接。实际应用中通常引入心跳机制(Ping/Pong)来检测连接健康状态。
总结
通过这八段 Python 代码,我们从零开始构建了 HTTP 的服务端和客户端(涵盖 GET 与 POST),又搭建了 WebSocket 的回声服务器、同步/异步客户端以及广播聊天室。这一过程完整覆盖了两种协议的核心通信模式。
牢记两个要点:
• HTTP 是“有问才答”——适用于常规数据获取和提交。
• WebSocket 是“随时畅聊”——适用于实时互动场景。
现在,打开你的代码编辑器,逐一运行这些示例,并尝试修改参数、增加功能。当你亲手让一条消息从客户端飞到服务端,再从服务端广播给多个客户端时,网络通信的原理就不再是抽象的文字,而是你能掌控的代码现实。
Excel图标 Word图标


客服1