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)
问题分析与解决方案
核心问题
- 单次
recv无法获取完整请求:TCP是流式协议,recv(1024)仅能读取最多1024字节数据,若请求(尤其是消息体)超过该长度或分批次发送,会直接丢失部分内容。 - 未按HTTP协议解析消息体:POST请求的消息体长度由请求头的
Content-Length字段指定,当前代码完全忽略该逻辑,仅处理了请求头部分。 - 响应格式错误:
RESPONSE字符串中的\\是多余转义符,会导致响应头不符合HTTP规范,可能引发客户端异常。 - 缺失端口绑定:原代码注释掉了
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()
关键修改说明
- 恢复端口绑定:重新启用
sock.bind(('',6920)),确保服务器能正常监听请求。 - 循环读取完整请求:通过循环调用
recv直到获取HTTP请求头结束符\r\n\r\n,再根据Content-Length读取完整消息体。 - 规范HTTP解析逻辑:拆分请求行、请求头与消息体,正确提取
Content-Length并读取对应长度的内容。 - 修复响应格式:移除
RESPONSE字符串中的多余转义符,确保响应符合HTTP协议规范。
内容的提问来源于stack exchange,提问作者alex hernandez
相关产品推荐
相关产品推荐

