计算机网络课设:用Flask+Socket实现可抓包验证的电子购物系统

发布时间:2026/10/7 17:54:19
计算机网络课设:用Flask+Socket实现可抓包验证的电子购物系统 简介本资源是一份面向高校计算机网络课程设计的完整实践方案专为本科生课程实训与网络工程初学者打造聚焦中小企业级电子购物网站的网络架构设计与服务部署。内容涵盖需求分析、拓扑规划、子网划分≥4个、IP地址分配、DNS/DHCP/WEB/FTP四大核心服务的软件选型与配置说明并附有简易WEB主页实现思路有效衔接TCP/IP模型、网络设备配置与服务器管理等关键知识点。压缩包为单个2.84MB的Word文档.doc结构清晰含前言、任务书、五章主体内容需求分析、拓扑结构、设备与子网配置、服务软件配置、界面设计及小结与参考文献文档内含详细配置步骤、参数说明与教学提示。目前已有2042人学习下载适合用于课程报告撰写、实验复现与网络系统设计能力强化。1. 计算机网络课程设计电子购物网站设计不是搭个网页而是用TCP/IP栈跑通一次真实交易闭环“计算机网络课程设计电子购物网站设计”——这标题乍看像前端作业实则是个典型的网络层应用层联合验证型实训项目。它不考你能不能用Vue写出漂亮界面而考你能否让一个HTTP请求从浏览器发出经DNS解析、TCP三次握手、HTTP状态码流转、服务器端Socket监听与响应、再到客户端完整接收并渲染全程可抓包、可调试、可复现。我带过6届网络课设90%的学生卡在“页面能打开但加购失败没报错Wireshark里却看不到POST数据”根源不是代码写错而是根本没理解应用层协议如何依赖传输层可靠交付、传输层又如何受网络层路由影响。这个设计真正要练的是用最小可行系统一个商品页购物车订单提交把OSI七层模型从纸面拉进Wireshark的Packet List里。适合刚学完谢希仁《计算机网络》第3~6章、正在啃TCP拥塞控制和HTTP状态机、需要把抽象协议具象化的本科生。别急着写HTML先让netstat -an | grep :8080能看到你的服务端口真正在LISTEN。2. 用Python Flask Socket实现双协议栈HTTP提供页面原始Socket处理关键事务课程设计最常翻车的点是把“电子购物网站”当成纯Web开发任务——用Django或Spring Boot一气呵成结果答辩时被问“请现场抓包展示三次握手过程”当场哑火。真正的网络课设必须暴露底层协议交互。我的做法是HTTP只负责静态资源分发和表单渲染所有核心业务逻辑添加购物车、生成订单走自定义TCP Socket通信。这样既能用浏览器访问又能用telnet localhost 9999直连调试Wireshark里清晰看到SYN/SYN-ACK/ACK、应用层自定义协议帧、FIN挥手全过程。2.1 搭建双协议服务框架Flask做门面Socket做内核先建基础目录结构shopping-system/ ├── app.py # Flask主服务HTTP ├── socket_server.py # 自定义TCP服务购物车/订单核心 ├── static/ │ ├── css/ │ └── js/ └── templates/ ├── index.html # 商品列表页 └── cart.html # 购物车页app.py只做三件事提供HTML页面、转发用户操作到Socket、返回Socket响应结果。关键不是渲染逻辑而是精准控制HTTP连接生命周期# app.py from flask import Flask, render_template, request, jsonify import socket import json app Flask(__name__) def send_to_socket(data): 向本地Socket服务发送JSON指令等待响应 try: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((localhost, 9999)) # 连接自定义Socket服务 s.sendall(json.dumps(data).encode(utf-8)) response s.recv(4096) return json.loads(response.decode(utf-8)) except Exception as e: return {status: error, msg: str(e)} app.route(/) def home(): return render_template(index.html) app.route(/api/add_to_cart, methods[POST]) def add_to_cart(): # 接收HTTP POST转为Socket指令 item_id request.json.get(item_id) qty request.json.get(qty, 1) result send_to_socket({ cmd: add, item_id: item_id, qty: qty }) return jsonify(result) if __name__ __main__: app.run(host0.0.0.0, port5000, debugTrue)注意这里send_to_socket每次请求都新建Socket连接模拟真实用户行为非长连接。若需测试TCP连接复用可改用socket.setdefaulttimeout(5)并复用连接对象但课程设计阶段建议保持简单——每个HTTP请求对应一次独立TCP会话便于Wireshark逐帧分析。2.2 实现Socket服务端手动解析协议帧暴露TCP状态细节socket_server.py才是网络课设的核心战场。它不依赖任何Web框架纯用socket模块实现强制你处理粘包、心跳、连接超时等真实问题# socket_server.py import socket import json import threading from datetime import datetime # 模拟内存数据库课程设计不引入MySQL聚焦网络层 cart_db {} def handle_client(conn, addr): print(f[{datetime.now().strftime(%H:%M:%S)}] 新连接: {addr}) while True: try: # 关键手动处理粘包用\r\n作为消息边界 data b while not data.endswith(b\r\n): chunk conn.recv(1024) if not chunk: break data chunk if not data: break # 解析JSON指令必须以\r\n结尾否则阻塞 try: cmd json.loads(data.strip().decode(utf-8)) response process_command(cmd) conn.sendall(json.dumps(response).encode(utf-8) b\r\n) except json.JSONDecodeError: conn.sendall(json.dumps({status: error, msg: Invalid JSON}).encode(utf-8) b\r\n) except ConnectionResetError: print(f[{datetime.now().strftime(%H:%M:%S)}] 连接重置: {addr}) break except Exception as e: print(f[{datetime.now().strftime(%H:%M:%S)}] 处理异常: {e}) break conn.close() print(f[{datetime.now().strftime(%H:%M:%S)}] 连接关闭: {addr}) def process_command(cmd): 处理购物车核心逻辑此处暴露TCP可靠性保障点 if cmd[cmd] add: item_id cmd[item_id] qty cmd.get(qty, 1) # 模拟库存检查网络课设重点不是业务而是状态同步 if item_id not in cart_db: cart_db[item_id] qty else: cart_db[item_id] qty return {status: success, cart_size: len(cart_db)} elif cmd[cmd] get_cart: return {status: success, items: list(cart_db.items())} else: return {status: error, msg: Unknown command} def start_server(): server_socket socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 关键参数SO_REUSEADDR避免端口占用 server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind((localhost, 9999)) server_socket.listen(5) print(Socket服务启动监听端口 9999...) while True: conn, addr server_socket.accept() # 为每个连接开独立线程课程设计不需高并发避免select/poll复杂度 client_thread threading.Thread(targethandle_client, args(conn, addr)) client_thread.daemon True client_thread.start() if __name__ __main__: start_server()为什么用\r\n做消息边界这是课程设计中必须亲手写的粘包处理——HTTP用\r\n\r\n分隔头/体SMTP用.结束你的自定义协议也得有明确帧定界符。Wireshark里能看到每个sendall()调用对应一个TCP Segment而recv()的阻塞行为直接体现TCP流式传输特性。若跳过这步直接用recv(4096)学生永远不懂“为什么抓包看到数据被拆成两包”。3. 用Wireshark抓包验证七层模型从DNS查询到HTTP 200 OK的完整链路课程设计验收时老师最想看到的不是页面多炫而是你能指着Wireshark的Packet List说清每一行代表哪一层。本节教你怎么用最小抓包集证明你的系统真正在跑TCP/IP栈而非仅靠浏览器渲染蒙混过关。3.1 设置过滤器聚焦三次握手、HTTP事务、Socket通信三类关键帧启动Wireshark后先设置捕获过滤器Capture Filter缩小范围避免海量无关包干扰tcp port 5000 or tcp port 9999 or udp port 53tcp port 5000捕获Flask HTTP服务通信tcp port 9999捕获自定义Socket通信udp port 53捕获DNS查询浏览器访问localhost:5000时自动触发开始捕获后在浏览器访问http://localhost:5000点击“加入购物车”再刷新购物车页。停止捕获用显示过滤器Display Filter分段分析过滤器表达式作用典型现象tcp.port 53 dns查看DNS解析过程可见Standard query A localhost→Standard query response A 127.0.0.1tcp.port 5000 http分析HTTP事务看到GET / HTTP/1.1→HTTP/1.1 200 OK注意Connection: keep-alive字段tcp.port 9999定位Socket通信找到[SYN]→[SYN, ACK]→[ACK]随后是你的JSON数据帧提示右键某条TCP包 → “Follow” → “TCP Stream”Wireshark会自动重组该连接的所有数据流。这是验证粘包处理是否正确的黄金方法——你发送的{cmd:add,item_id:A001}\r\n必须在Stream里完整显示不能被截断或拼接。3.2 关键帧解读手把手教你读懂Wireshark里的网络真相以点击“加入购物车”为例抓包中必出现以下四组帧按时间顺序DNS查询UDP 53端口现象Standard query A localhost无响应→Standard query A 127.0.0.1有响应为什么重要证明你的浏览器真走了DNS解析流程。若直接命中hosts文件Wireshark里看不到UDP 53包需手动ping localhost触发DNS。TCP三次握手端口5000现象[SYN] Seq0→[SYN, ACK] Seq0 Ack1→[ACK] Seq1 Ack1血泪经验若第二步[SYN, ACK]没出现检查Flask是否真在LISTENnetstat -an | grep :5000。常见错误是app.run()没加host0.0.0.0导致只监听127.0.0.1Wireshark抓不到。HTTP POST请求端口5000现象POST /api/add_to_cart HTTP/1.1→HTTP/1.1 200 OK注意点查看Content-Length是否匹配实际JSON长度Connection字段是否为keep-alive证明HTTP/1.1复用连接。Socket通信端口9999现象[SYN]→[SYN, ACK]→[ACK]→{cmd:add,item_id:A001}\r\n→{status:success}\r\n→[FIN, ACK]玄学排查若看到[RST]包说明Socket服务未启动或端口被占若JSON数据后没有\r\nrecv()会一直阻塞——这就是你亲手写的粘包处理在起作用。4. 避坑指南课程设计中最常踩的5个网络层陷阱及现场急救方案网络课设的崩溃点90%不在代码语法而在对协议栈的理解偏差。以下是我在实验室亲眼见过、学生反复提交失败的5个典型问题附带Wireshark定位法和一行命令急救方案。4.1 现象页面能打开但“加入购物车”按钮点击无反应浏览器控制台无报错原因Flask服务监听127.0.0.1:5000而AJAX请求发向localhost:5000在部分系统如WSL2中localhost≠127.0.0.1DNS解析失败导致请求超时。解决检查Flask启动日志是否含* Running on all addresses即host0.0.0.0终端执行curl -v http://127.0.0.1:5000/api/add_to_cart -H Content-Type: application/json -d {item_id:A001}若curl成功但浏览器失败说明是跨域或DNS问题临时在/etc/hosts加127.0.0.1 localhost4.2 现象Wireshark抓到大量[TCP Retransmission]包Socket通信极慢原因自定义Socket服务未设置SO_KEEPALIVE客户端短连接频繁创建销毁触发TCP TIME_WAIT堆积端口耗尽。解决在socket_server.py的server_socket创建后添加server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) server_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 60) server_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 10) server_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 3)或更简单重启前执行sudo ss -s查看TIME_WAIT数量若2000用sudo sysctl -w net.ipv4.tcp_fin_timeout30临时缩短超时。4.3 现象购物车数据偶尔丢失Wireshark里看到[TCP Dup ACK]原因内存数据库cart_db非线程安全多用户并发修改导致数据覆盖。课程设计虽不强调并发但浏览器多标签页即触发竞态。解决在process_command函数开头加锁import threading cart_lock threading.Lock() # 全局锁 def process_command(cmd): with cart_lock: # 关键包裹所有读写操作 if cmd[cmd] add: # ...原有逻辑验证开两个浏览器标签页同时加购Wireshark应看到两个独立TCP流且cart_size累加正确。4.4 现象telnet localhost 9999能连上但发送JSON后无响应Wireshark显示[TCP segment of a reassembled PDU]原因未按约定发送\r\n结尾Socket服务端recv()阻塞等待消息边界。解决telnet中输入后务必按Ctrl]→send→ 输入\r\n或直接用echo {cmd:get_cart} | nc localhost 9999在socket_server.py的handle_client里加日志print(fRaw recv: {data!r})确认收到\r\n4.5 现象答辩时老师用另一台电脑访问http://[本机IP]:5000打不开原因防火墙阻止外部访问或Flask未绑定0.0.0.0。解决WindowsWindows Defender 防火墙→高级设置→入站规则→ 新建规则 → 端口5000→ 允许连接Linuxsudo ufw allow 5000代码确认app.run(host0.0.0.0, port5000)而非host127.0.0.15. 进阶验证用tc工具注入网络故障证明你的系统具备容错韧性课程设计的高分关键不是功能完整而是能主动制造并应对网络异常。很多学生做到“能跑通”就停了但老师真正想考察的是当丢包、延迟、乱序发生时你的TCP连接是否自动重传HTTP请求是否超时重试购物车数据是否因连接中断而丢失本节教你用Linux自带的tcTraffic Control工具在本地模拟真实网络病态用Wireshark和日志双重验证系统健壮性。5.1 注入20%随机丢包检验TCP重传机制是否生效在终端执行需root权限# 对回环接口lo注入丢包影响localhost通信 sudo tc qdisc add dev lo root netem loss 20% # 验证ping自己应看到约20%丢包率 ping -c 10 127.0.0.1 | grep packet loss此时再访问http://localhost:5000Wireshark中将密集出现[TCP Retransmission]和[TCP Spurious Retransmission]。重点观察Flask的HTTP响应是否仍能到达TCP自动重传保障Socket通信中{cmd:add}指令是否最终成功你的send_to_socket函数是否带重试逻辑若购物车始终为空说明你的Socket客户端没处理超时——立即补上# 在app.py的send_to_socket函数中 def send_to_socket(data): for attempt in range(3): # 最多重试3次 try: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.settimeout(5) # 关键设置超时否则永久阻塞 s.connect((localhost, 9999)) s.sendall(json.dumps(data).encode(utf-8)) response s.recv(4096) return json.loads(response.decode(utf-8)) except (socket.timeout, ConnectionRefusedError) as e: if attempt 2: raise e time.sleep(0.5) # 指数退避可选5.2 注入100ms固定延迟验证HTTP连接复用与Keep-Alive有效性# 清除之前规则 sudo tc qdisc del dev lo root # 添加100ms延迟 sudo tc qdisc add dev lo root netem delay 100ms # 测试curl两次对比时间差 time curl -s http://localhost:5000 /dev/null time curl -s http://localhost:5000 /dev/null若第二次耗时显著减少如从105ms降到5ms说明HTTP Keep-Alive生效复用了TCP连接若两次时间相近检查Flask响应头是否含Connection: keep-alive默认开启除非显式关闭。5.3 模拟网络分区拔掉网线再插回检验Session恢复能力这是最贴近生产环境的测试。操作步骤启动Flask和Socket服务浏览器打开http://localhost:5000加入商品到购物车物理拔掉网线或禁用Wi-Fi等待30秒重新插回网线刷新页面预期结果页面应正常加载HTTP服务在本地不受外网影响购物车数据仍在因cart_db在内存非分布式Session若你扩展了Redis存储则需验证Redis连接自动重连我的血泪教训第一次做课设时我花3天调通功能却在答辩前2小时发现tc注入丢包后购物车清空——根源是Socket客户端没设settimeout()导致recv()无限等待Flask主线程卡死。从此养成习惯任何socket.recv()前必设超时任何requests.post()必加timeout(3, 10)。网络编程里超时不是可选项是生存底线。希望帮到你。本文还有配套的精品资源点击获取