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

Python TCP服务器recv(1024)无法稳定接收POST请求体问题求助

问题描述

我搭建了一个TCP服务器,客户端通过POST请求连接时,有时能获取完整的请求头,但始终无法接收到POST消息体。


服务器代码

#tcp server
import socket
import urllib.request

# issues with rev()
#https://stackoverflow.com/questions/7174927/when-does-socket-recvrecv-size-return

external_ip = urllib.request.urlopen('https://ident.me').read().decode('utf8')
print("v6 ip:",external_ip)

#socket AF_INET = v4
#socket AF_INET6 = v6
sock = socket.socket(socket.AF_INET6 , socket.SOCK_STREAM)
#sock.bind(('',6920))
sock.listen(100)

RESPONSE = """HTTP/1.1 200 OK\r\n\\
Date: Mon, 27 Jul 2009 12:28:53 GMT\r\n\\
Server: Apache/2.2.14 (Win32)\r\n\\
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT\r\n\\
Content-Length: {length}\r\n\\
Content-Type: text/html\r\n\\
Connection: Closed\r\n\r\n\\
{body}
"""
total_clients = 0
while True:
    clients = []
 
    while True:

        clientsocket , address = sock.accept()
      
        clients.append(clientsocket)
        #total_clients += total_clients +1
        if len(clients) == 1:
            #print('got 2 clients, sending details to each')
            #total_clients += total_clients +1
            print("client revieve " , )

            data = clientsocket.recv(1024)
            fields = data.decode().split("\r\n")
            fields = fields[1:]
            output = {}
            for field in fields:
              #print("filed", field)
              if ":" in field:
                key, value = field.split(":" , 1)
                output[key] = value
                pass
                
            #print("data json :", output)

            if "client_info" in output:
              print(output["client_info"])
           
            break
       
        #clientsocket.send(bytes(str("hello my dudes"),"utf-8"))
      
  
    c1 = clients.pop()
    #c1_addr_port= c1
    #c2 = clients.pop()
    #c1_addr_port = c2

    text = """hello my dudes"""

    content_length = len(text.encode("utf-8"))
    response = RESPONSE.format(length=content_length, body=text)
    c1.send(response.encode("utf-8"))
   # c2.send(response.encode("utf-8"))

客户端代码

import requests 
url = 'https://server.alexhernandez11.repl.co'
#x = requests.get(url)

my_text = 'hello sending info121'
info = my_text.encode('utf-8')

x = requests.post(url, data = info)

print(x.content)

问题分析与解决方案

核心问题

  1. 单次recv无法获取完整请求:TCP是流式协议,recv(1024)仅能读取最多1024字节数据,若请求(尤其是消息体)超过该长度或分批次发送,会直接丢失部分内容。
  2. 未按HTTP协议解析消息体:POST请求的消息体长度由请求头的Content-Length字段指定,当前代码完全忽略该逻辑,仅处理了请求头部分。
  3. 响应格式错误:RESPONSE字符串中的\\是多余转义符,会导致响应头不符合HTTP规范,可能引发客户端异常。
  4. 缺失端口绑定:原代码注释掉了sock.bind(('',6920)),导致服务器无法正常监听端口,这是基础运行问题。

修正后的服务器代码

# TCP server
import socket
import urllib.request

external_ip = urllib.request.urlopen('https://ident.me').read().decode('utf8')
print("v6 ip:", external_ip)

sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.bind(('', 6920))
sock.listen(100)

# 修复响应字符串的多余转义
RESPONSE = """HTTP/1.1 200 OK\r
Date: Mon, 27 Jul 2009 12:28:53 GMT\r
Server: Custom TCP Server\r
Content-Length: {length}\r
Content-Type: text/html\r
Connection: Closed\r
\r
{body}
"""

def parse_http_request(client_socket):
    # 循环读取直到拿到完整请求头
    raw_data = b''
    while b'\r\n\r\n' not in raw_data:
        chunk = client_socket.recv(1024)
        if not chunk:
            break
        raw_data += chunk

    # 分割请求头与消息体
    header_part, body_part = raw_data.split(b'\r\n\r\n', 1)
    header_text = header_part.decode('utf-8')
    fields = header_text.split('\r\n')
    
    # 解析请求行
    request_line = fields[0]
    method, path, _ = request_line.split(' ', 2)
    
    # 解析请求头,提取Content-Length
    headers = {}
    content_length = 0
    for field in fields[1:]:
        if ':' in field:
            key, value = field.split(':', 1)
            key = key.strip()
            headers[key] = value.strip()
            if key.lower() == 'content-length':
                content_length = int(value.strip())
    
    # 读取剩余消息体(若已读取的body_part长度不足Content-Length)
    remaining = content_length - len(body_part)
    if remaining > 0:
        while remaining > 0:
            chunk = client_socket.recv(min(remaining, 1024))
            if not chunk:
                break
            body_part += chunk
            remaining -= len(chunk)
    
    return method, headers, body_part.decode('utf-8')

while True:
    clientsocket, address = sock.accept()
    print(f"收到来自 {address} 的连接")
    
    try:
        method, headers, body = parse_http_request(clientsocket)
        print(f"请求方法: {method}")
        print(f"请求头: {headers}")
        print(f"POST消息体: {body}")
        
        # 构造响应
        text = f"收到你的消息: {body}"
        content_length = len(text.encode('utf-8'))
        response = RESPONSE.format(length=content_length, body=text)
        clientsocket.send(response.encode('utf-8'))
    except Exception as e:
        print(f"处理请求出错: {e}")
    finally:
        clientsocket.close()

关键修改说明

  1. 恢复端口绑定:重新启用sock.bind(('',6920)),确保服务器能正常监听请求。
  2. 循环读取完整请求:通过循环调用recv直到获取HTTP请求头结束符\r\n\r\n,再根据Content-Length读取完整消息体。
  3. 规范HTTP解析逻辑:拆分请求行、请求头与消息体,正确提取Content-Length并读取对应长度的内容。
  4. 修复响应格式:移除RESPONSE字符串中的多余转义符,确保响应符合HTTP协议规范。

内容的提问来源于stack exchange,提问作者alex hernandez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 12:30:42