我要在openwrt上实现一个文件读取的功能。用python脚本写一个客户端请求服务器,服务器基于openwrt开发。我将提供给你服务器和客户端的代码,客户端打印:============================================================
Device Log Retrieval Client
============================================================
2025-10-20 19:22:52,316 [INFO] Network path to 192.168.137.19:21443 is accessible
2025-10-20 19:22:52,318 [DEBUG] Starting new HTTPS connection (1): 192.168.137.19:21443
2025-10-20 19:22:52,484 [DEBUG] https://192.168.137.19:21443 "GET /log/file_log_get HTTP/1.1" 200 1063654
2025-10-20 19:22:52,492 [ERROR] Unexpected error: ('Connection broken: IncompleteRead(0 bytes read, 1063654 more expected)', IncompleteRead(0 bytes read, 1063654 more expected))
Log retrieval failed! Review error messages above
============================================================请你在此基础上分析错误的原因并改正。 if (!strncmp(sock->parser.http.url, "/log/file_log_get", sizeof("/log/file_log_get"))) {
if (false == worker_file_log_read_handle(handler->priv, sock, buf)) {
tpsocket_free_buf(buf, tpsocket_event_name(event), 0);
return false;
}
}bool worker_file_log_read_handle(WORKER_CTX *worker_ctx, struct tpsocket_fd *sock, struct list_head *buf)
{
char *mac = common_find_key_from_buf(buf, "Device-Mac");
if (!mac || strlen(mac) < 12) {
DBG_ERR("Invalid MAC address\n");
const char *resp = "HTTP/1.1 400 Bad Request\r\n\r\n";
struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp);
if (resp_buf) tpsocket_write(sock, resp_buf);
return false;
}
DBG_ERR("mac: %s\n", mac);
char processed_mac[18] = {0};
strncpy(processed_mac, mac, sizeof(processed_mac)-1);
for (char *p = processed_mac; *p; p++) if (*p == ':') *p = '_';
// 3. 构建日志文件路径
char filepath[256];
snprintf(filepath, sizeof(filepath), "%s/%s/log.txt", FILELOG_PATH, processed_mac);
DBG_ERR("filepath: %s\n", filepath);
// 4. 检查文件是否存在
if (access(filepath, F_OK) != 0) {
DBG_ERR("Log file not found: %s\n", filepath);
const char *resp = "HTTP/1.1 404 Not Found file\r\n\r\n";
struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp);
if (resp_buf) tpsocket_write(sock, resp_buf);
return false;
}
// 5. 打开日志文件
FILE *fp = fopen(filepath, "r");
if (!fp) {
DBG_ERR("Failed to open log file: %s\n", strerror(errno));
const char *resp = "HTTP/1.1 500 Internal Error\r\n\r\n";
struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp);
if (resp_buf) tpsocket_write(sock, resp_buf);
return false;
}
DBG_ERR("[SUCCESS] File opened successfully\n");
// 6. 获取文件大小 (假设最大5MB)
struct stat st;
if (fstat(fileno(fp), &st) != 0) {
DBG_ERR("Failed to get file size: %s\n", strerror(errno));
fclose(fp);
const char *resp = "HTTP/1.1 500 Internal Error\r\n\r\n";
struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp);
if (resp_buf) tpsocket_write(sock, resp_buf);
return false;
}
size_t file_size = st.st_size;
DBG_ERR("[DEBUG] File size: %zu bytes\n", file_size);
ReadLogSession *session = calloc(1, sizeof(ReadLogSession));
if (!session) return false;
session->fp = fp;
session->file_size = st.st_size;
session->header_sent = false;
session->sent_bytes = 0;
session->transfer_complete = false;
snprintf(session->filepath,sizeof(session->filepath),"%s",filepath);
// 8. 设置回调处理
sock->handler.cb = tpsocket_event_filelog_from_hub;
sock->handler.priv = session;
DBG_ERR("[DEBUG] File opened for streaming: %zu bytes\n", session->file_size);
return true;
}bool tpsocket_event_filelog_from_hub(struct tpsocket_handler *handler, struct list_head *buf, int event)
{
struct tpsocket_fd *sock = container_of(handler, struct tpsocket_fd, handler);
ReadLogSession *session = handler->priv;
if (event != TPSOCKET_EVENT_STREAM) {
DBG_ERR("sock=%p, event=%s\n", sock, tpsocket_event_name(event));
}
#define TRANSFER_CHUNK_SIZE 64*1024
char chunk_buf[TRANSFER_CHUNK_SIZE];
switch(event) {
case TPSOCKET_EVENT_LISTEN:
DBG_ERR("TPSOCKET_EVENT_LISTEN");
break;
case TPSOCKET_EVENT_SHUTDOWN:
DBG_ERR("TPSOCKET_EVENT_SHUTDOWN");
break;
case TPSOCKET_EVENT_ACCEPT:
DBG_ERR("TPSOCKET_EVENT_ACCEPT");
break;
case TPSOCKET_EVENT_CONNECTED:
break;
case TPSOCKET_EVENT_REQ_HEAD:
DBG_ERR("TPSOCKET_EVENT_REQ_HEAD");
break;
case TPSOCKET_EVENT_RSP_HEAD:
DBG_ERR("TPSOCKET_EVENT_RSP_HEAD");
break;
case TPSOCKET_EVENT_SUB_HEAD:
break;
case TPSOCKET_EVENT_UPGRADE:
break;
case TPSOCKET_EVENT_WRITABLE:
DBG_ERR("TPSOCKET_EVENT_WRITABLE");
// if (session && session->transfer_complete) {
// // 传输完成,关闭连接并释放资源
// free(session);
// handler->priv = NULL;
// tpsocket_close(sock);
// }
break;
case TPSOCKET_EVENT_STREAM:
case TPSOCKET_EVENT_MESSAGE:
DBG_ERR("TPSOCKET_EVENT_MESSAGE");
if (!session || !session->fp) {
DBG_ERR("Invalid session during transfer\n");
return false;
}
// 1. 发送HTTP头
if (!session->header_sent) {
char header[512];
int header_len = snprintf(header, sizeof(header),
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: %zu\r\n"
"Connection: close\r\n\r\n",
session->file_size);
if (header_len <= 0) {
DBG_ERR("Header generation failed\n");
return false;
}
struct tpsocket_buf *header_buf = tpbuf_snprintf(header_len + 1, header);
if (!header_buf || !tpsocket_write(sock, header_buf)) {
DBG_ERR("Failed to send header\n");
return false;
}
session->header_sent = true;
DBG_ERR("HTTP header sent\n");
}
DBG_ERR("Start sent body\n");
// 确保不会重复发送文件内容
if (!session->transfer_started) {
session->transfer_started = true;
while (!feof(session->fp)) {
size_t bytes_read = fread(chunk_buf, 1, sizeof(chunk_buf), session->fp);
if (bytes_read > 0) {
struct tpsocket_buf *data_buf = tpbuf_new(bytes_read);
if (!data_buf) {
DBG_ERR("buf allocation failed");
return false;
}
memcpy(data_buf->data, chunk_buf, bytes_read);
if (!tpsocket_write(sock, data_buf)) {
DBG_ERR("Socket write failed");
tpbuf_free(data_buf);
return false;
}
session->sent_bytes += bytes_read;
// 打印进度
DBG_ERR("-----------------: %.1f%% (%zu/%zu)",
(double)session->sent_bytes/session->file_size * 100,
session->sent_bytes, session->file_size);
}
}
session->transfer_complete = true;
fclose(session->fp); // 及时关闭文件
session->fp = NULL;
}
// 3. 传输完成处理
DBG_ERR("---------------------------%zu/%zu", session->sent_bytes, session->file_size);
// 4. 清理资源
// fclose(session->fp);
// free(session);
// handler->priv = NULL;
// session->transfer_complete = true;
// tpsocket_close(sock);
break;
case TPSOCKET_EVENT_CLOSED:
if (session) {
if (session->fp) fclose(session->fp);
free(session);
handler->priv = NULL;
}
break;
case TPSOCKET_EVENT_ERROR:
default:
break;
}
return true;
}客户端代码:import requests
import logging
import socket
import time
from urllib.parse import urlencode
# Disable HTTPS certificate warnings
requests.packages.urllib3.disable_warnings()
def get_device_logs(server_ip: str = "192.168.137.19", port: int = 21443,
mac_address: str = "A1:B2:C3:D4:E5:F6", timeout: int = 15):
"""
Optimized device log retrieval client with robust error handling
"""
# 1. Configure URL and headers
url = f"https://{server_ip}:{port}/log/file_log_get"
headers = {
"Device-Mac": mac_address.replace(":", "_"),
"Connection": "close" # 改为保持连接
}
# 2. Configure detailed logging (English only)
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[logging.StreamHandler()]
)
# 3. Network pre-check
try:
sock = socket.create_connection((server_ip, port), timeout=5)
sock.close()
logging.info(f"Network path to {server_ip}:{port} is accessible")
except socket.error as e:
logging.error(f"Network unreachable: {str(e)}")
return None
MAX_RETRIES = 1
for attempt in range(MAX_RETRIES):
try:
start_time = time.time()
# 4. Optimized request parameters
response = requests.get(
url,
headers=headers,
verify=False,
timeout=(3, timeout), # Connect timeout 3s, read timeout custom
stream=True
)
elapsed = time.time() - start_time
logging.info(f"HTTP response received! Time: {elapsed:.2f}s, Status: {response.status_code}")
if response.status_code == 200:
content = bytearray()
expected_length = int(response.headers.get('Content-Length', 0))
received_length = 0
try:
# 5. Robust chunk handling
last_receive_time = time.time()
chunk_counter = 0 # 新增:chunk计数器
logging.info(f"Starting data stream reception | Expected size: {expected_length} bytes")
for chunk in response.iter_content(chunk_size=10240):
logging.info(f"enterd")
current_time = time.time()
chunk_counter += 1 # 更新chunk计数
# 5.1 Chunk timeout detection
time_since_last = current_time - last_receive_time
if time_since_last > 10:
logging.error(f"Data reception timeout | Last chunk: {time_since_last:.1f}s ago | Received {chunk_counter} chunks")
break
if chunk:
chunk_size = len(chunk) # 记录当前chunk大小
# 新增:记录接收细节
logging.debug(f"Chunk #{chunk_counter} received | Size: {chunk_size} bytes | Cumulative: {received_length + chunk_size} bytes")
content.extend(chunk)
received_length += chunk_size
last_receive_time = current_time
# 5.2 Progress tracking
if expected_length > 0:
percent = (received_length / expected_length) * 100
# 新增:增加进度细节
logging.info(f"[Progress] {percent:.1f}% ({received_length}/{expected_length} bytes) | Chunks: {chunk_counter}")
else:
# 新增:记录空chunk的时间戳
logging.debug(f"Received empty keep-alive chunk | Time: {time.strftime('%H:%M:%S', time.localtime(current_time))}")
# 新增:传输结束总结
logging.info(f"Stream transmission completed | Total chunks: {chunk_counter} | Total bytes: {received_length}")
# 6. Enhanced error handling
except requests.exceptions.ConnectionError as e:
logging.error(f"Transfer interrupted: {str(e)}")
except requests.exceptions.Timeout:
logging.error("Stream transfer timeout!")
except requests.exceptions.ChunkedEncodingError as e:
logging.error(f"Chunk encoding error: {str(e)}")
# 7. Data integrity verification
if expected_length > 0 and received_length != expected_length:
logging.error(f"Incomplete transfer! Received {received_length}/{expected_length} bytes")
elif received_length > 0:
logging.info("Data transfer completed successfully")
return content.decode('utf-8', errors='replace')
else:
logging.warning("Received empty response payload")
# 8. HTTP error handling
logging.error(f"Request failed! Status: {response.status_code}")
if response.status_code >= 400:
logging.error(f"Response headers: {dict(response.headers)}")
# 9. Top-level exception handling
except requests.exceptions.SSLError as e:
logging.error(f"SSL handshake failed: {str(e)}")
except requests.exceptions.ConnectionError:
logging.error("Connection failure! Verify: 1) Network connectivity 2) Service status 3) Firewall rules")
except requests.exceptions.Timeout:
logging.error(f"Global timeout reached ({timeout}s)! Solutions: 1) Check network 2) Increase timeout")
except Exception as e:
logging.error(f"Unexpected error: {str(e)}")
return None
def build_debug_url(server_ip: str, port: int, mac: str) -> str:
"""Generate debug URL with MAC parameter"""
params = {"mac": mac.replace(":", "_")}
return f"https://{server_ip}:{port}/debug?{urlencode(params)}"
if __name__ == "__main__":
print("=" * 60)
print("Device Log Retrieval Client")
print("=" * 60)
logs = get_device_logs(
server_ip="192.168.137.19",
port=21443,
mac_address="A1:B2:C3:D4:E5:F6",
timeout=20
)
if logs:
print("\n" + "=" * 20 + " LOG CONTENT START " + "=" * 20)
print(logs[:2000] + ("..." if len(logs)>2000 else ""))
print("=" * 20 + " LOG CONTENT END " + "=" * 20)
print(f"\nLog retrieval successful! Total length: {len(logs)} characters")
debug_url = build_debug_url("192.168.137.19", 21443, "A1:B2:C3:D4:E5:F6")
print(f"Debug tip: Visit {debug_url} for server diagnostics")
else:
print("Log retrieval failed! Review error messages above")
print("=" * 60)
帮我解决。