You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Wireshark捕获HTTP GET图片请求但Socket的recv()无法接收

问题根源分析
  • HTTP响应不规范:你的response.txt仅包含HTTP/1.1 200 OK状态行,缺少HTTP协议要求的核心响应头——比如Content-Type(告知浏览器返回内容的类型)、Content-Length(告知浏览器响应体的字节长度),以及Connection头。Chrome在HTTP/1.1下默认启用持久连接(Keep-Alive),如果服务器未明确标记响应结束或指定连接状态,浏览器会一直等待剩余数据,导致后续请求的数据流被阻塞。
  • 未处理连接断开场景:conn.recv()在客户端主动断开连接时会返回空字节串b'',你的代码未对该情况做判断,会陷入死循环,无法正确识别新请求的边界。
  • 请求解析逻辑脆弱:假设每次recv()都能完整接收一个HTTP请求,但TCP是流式传输,请求可能被拆分为多个数据包到达;同时,当请求行解析失败时(比如line01member长度不足),代码仅打印错误却继续执行,会导致后续open(token)抛出未捕获的异常。
  • 文件路径处理错误:当请求图片/w3logo.jpg时,代码直接用token = line01member[1][1:]得到w3logo.jpg,但未指定正确的文件目录,会在当前工作目录下查找,而非HTML文件所在的目录,大概率导致文件找不到。
修复后的代码
import socket
import os
import sys

HOST = '192.168.43.157'  
PORT = 80
# 网站根目录,将HTML、图片等资源统一放在这里
WEB_ROOT = r"C:\Users\Totz Tech\Videos"

def get_content_type(file_path):
    # 根据文件后缀返回对应的Content-Type
    ext = os.path.splitext(file_path)[1].lower()
    if ext == '.html':
        return 'text/html; charset=utf-8'
    elif ext in ('.jpg', '.jpeg'):
        return 'image/jpeg'
    elif ext == '.png':
        return 'image/png'
    else:
        return 'application/octet-stream'

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('# Socket created')

try:
    s.bind((HOST, PORT))
except socket.error as msg:
    print(f'# Bind failed: {msg}')
    sys.exit()

print('# Socket bind complete')
s.listen(10)
print('# Socket now listening')

while True:
    # 循环等待新连接,支持多客户端/同一客户端的多次请求
    conn, addr = s.accept()
    print(f'# Connected to {addr[0]}:{addr[1]}')
    
    try:
        # 接收请求数据(简单处理,假设请求不超过1024字节)
        data = conn.recv(1024)
        if not data:
            conn.close()
            continue
        
        request = data.decode('utf-8')
        # 解析请求行
        request_lines = request.split('\r\n')
        if not request_lines:
            conn.close()
            continue
        
        request_line = request_lines[0].strip()
        if not request_line:
            conn.close()
            continue
        
        parts = request_line.split()
        if len(parts) < 2:
            # 返回400错误:无效请求
            response = b'HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\nConnection: close\r\n\r\n'
            conn.send(response)
            conn.close()
            continue
        
        method, path, _ = parts
        if method != 'GET':
            # 仅处理GET请求
            response = b'HTTP/1.1 405 Method Not Allowed\r\nContent-Length: 0\r\nConnection: close\r\n\r\n'
            conn.send(response)
            conn.close()
            continue
        
        # 处理根路径请求
        if path == '/':
            file_path = os.path.join(WEB_ROOT, 'mypage.html')
        else:
            # 防止路径遍历攻击,限制仅访问WEB_ROOT内的文件
            file_path = os.path.join(WEB_ROOT, path.lstrip('/'))
            if not os.path.abspath(file_path).startswith(os.path.abspath(WEB_ROOT)):
                response = b'HTTP/1.1 403 Forbidden\r\nContent-Length: 0\r\nConnection: close\r\n\r\n'
                conn.send(response)
                conn.close()
                continue
        
        # 检查文件是否存在
        if not os.path.exists(file_path) or not os.path.isfile(file_path):
            response = b'HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\nConnection: close\r\n\r\n'
            conn.send(response)
            conn.close()
            continue
        
        # 读取文件内容
        with open(file_path, 'rb') as f:
            file_content = f.read()
        
        # 构建完整的HTTP响应
        content_type = get_content_type(file_path)
        response_headers = (
            f'HTTP/1.1 200 OK\r\n'
            f'Content-Type: {content_type}\r\n'
            f'Content-Length: {len(file_content)}\r\n'
            f'Connection: close\r\n'  # 关闭连接,避免持久连接导致的阻塞
            f'\r\n'  # 空行分隔响应头和响应体
        ).encode('utf-8')
        
        # 发送响应
        conn.send(response_headers + file_content)
        print(f'Sent {file_path} to {addr[0]}')
        
    except Exception as e:
        print(f'Error handling request: {e}')
    finally:
        # 确保连接关闭
        conn.close()

s.close()
关键修复点说明
  • 规范HTTP响应:添加Content-Type、Content-Length和Connection: close头,明确告知浏览器响应结束并关闭连接,避免持久连接导致的阻塞问题。
  • 异常与边界处理:判断recv()返回空的情况,处理无效请求、非GET请求等场景,避免死循环和未捕获异常。
  • 安全路径控制:用WEB_ROOT统一管理静态资源,防止路径遍历攻击,确保仅访问指定目录内的文件。
  • 多类型资源支持:根据文件后缀返回正确的Content-Type,让浏览器能正确解析HTML、图片等资源。
  • 循环接受连接:外层添加循环,支持多个客户端或同一客户端的多次请求(每次请求后关闭连接)。

内容的提问来源于stack exchange,提问作者The Mr. Totardo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 21:00:08