tcp_simple_manager添加dnscache功能
author孙春阳 <snickersun@163.com>
Sun, 10 Aug 2025 21:32:47 +0000 (05:32 +0800)
committer孙春阳 <snickersun@163.com>
Sun, 10 Aug 2025 21:32:47 +0000 (05:32 +0800)
code/sdk/drivers/peripheral/slip/tcpmanager/tcp_manager_at_cmd.c
code/sdk/drivers/peripheral/slip/tcpmanager/tcp_manager_test.c
code/sdk/drivers/peripheral/slip/tcpmanager/tcp_simple_manager.c
code/sdk/drivers/peripheral/slip/tcpmanager/tcp_simple_manager.h
ws_lwip_test/tcp_test_server.py

index 9752134..def7e96 100644 (file)
@@ -391,6 +391,60 @@ static uint32_t tcp_stress_test_cmd(uint8_t *para, uint32_t paraLen, char *strCo
     }
 }
 
+
+
+/**
+ * TCP管理命令
+ * 格式: AT^TCPCMD <command>
+ * 示例: AT^TCPCMD DNSCACHE
+ */
+static uint32_t tcp_manager_cmd(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    (void)strCommonCmd;
+    
+    printf("TCP管理命令: AT^TCPCMD\n");
+    
+    if (paraLen == 0 || para == NULL) {
+        printf("用法: AT^TCPCMD <命令>\n");
+        printf("支持的命令:\n");
+        printf("  STATUS - 显示状态信息\n");
+        printf("  DNSCACHE - 显示DNS缓存状态\n");
+        return ERRCODE_FAIL;
+    }
+    
+    char cmd[64];
+    snprintf(cmd, sizeof(cmd), "%.*s", (int)paraLen, (char*)para);
+    
+    if (strcmp(cmd, "STATUS") == 0) {
+        if (!g_tcp_manager_inited) {
+            printf("错误: TCP管理器未初始化\n");
+            return ERRCODE_FAIL;
+        }
+        
+        tcp_manager_stats_t stats;
+        tcp_get_manager_stats(&stats);
+        printf("=== TCP管理器状态 ===\n");
+        printf("总连接数: %u\n", stats.total_connections);
+        printf("活跃连接数: %u\n", stats.active_connections);
+        printf("发送字节数: %u\n", stats.bytes_sent);
+        printf("接收字节数: %u\n", stats.bytes_received);
+        printf("错误计数: %u\n", stats.errors);
+        printf("=====================\n");
+    } else if (strcmp(cmd, "DNSCACHE") == 0) {
+        if (!g_tcp_manager_inited) {
+            printf("错误: TCP管理器未初始化\n");
+            return ERRCODE_FAIL;
+        }
+        
+        tcp_show_dns_cache();
+    } else {
+        printf("未知命令: %s\n", cmd);
+        return ERRCODE_FAIL;
+    }
+    
+    return ERRCODE_SUCC;
+}
+
 /* AT命令表 */
 static const at_cmd_table_t g_tcp_manager_cmd[] = {
     { (char *)"AT^TCPINIT",      tcp_manager_init_cmd, (char *)"1" },
@@ -400,6 +454,7 @@ static const at_cmd_table_t g_tcp_manager_cmd[] = {
     { (char *)"AT^TCPSEND",      tcp_send_cmd, (char *)"1" },
     { (char *)"AT^TCPSTATUS",    tcp_status_cmd, (char *)"1" },
     { (char *)"AT^TCPTEST",      tcp_stress_test_cmd, (char *)"1" },
+    { (char *)"AT^TCPCMD",       tcp_manager_cmd, (char *)"1" },
 };
 
 /**
index 4ad0ad7..4f55932 100644 (file)
@@ -66,16 +66,22 @@ static tcp_stress_test_t g_stress_test = {0};
 /* 压力测试回调函数 */
 static void stress_test_on_connect(tcp_handle_t handle, bool success)
 {
+    printf("DEBUG: stress_test_on_connect 被调用: handle=%p, success=%d\n", handle, success);
+    
     /* 查找对应的连接 */
     tcp_stress_connection_t *conn = NULL;
     for (int i = 0; i < TCP_MANAGER_MAX_CONNECTIONS; i++) {
         if (g_stress_test.connections[i].handle == handle) {
             conn = &g_stress_test.connections[i];
+            printf("DEBUG: 找到连接 %d: conn_id=%d\n", i, conn->conn_id);
             break;
         }
     }
     
-    if (!conn) return;
+    if (!conn) {
+        printf("DEBUG: 警告: 找不到对应的连接 handle=%p\n", handle);
+        return;
+    }
     
     if (success) {
         conn->connected = true;
@@ -539,7 +545,34 @@ int tcp_manager_stress_test(const char* host, uint16_t port, uint32_t test_durat
     
     /* 等待TCP管理器完成清理 */
     printf("等待TCP管理器清理完成...\n");
-    sys_msleep(2000);
+    /* 分多次检查,确保TCP连接正常关闭 */
+    for (int wait_round = 0; wait_round < 10; wait_round++) {
+        sys_msleep(1000);  /* 每次等待1秒 */
+        
+        /* 检查连接状态 */
+        tcp_manager_stats_t current_stats;
+        if (tcp_get_manager_stats(&current_stats) == TCP_MANAGER_OK) {
+            printf("第%d次检查: 活跃连接=%u\n", wait_round + 1, current_stats.active_connections);
+            if (current_stats.active_connections == 0) {
+                printf("所有连接已成功关闭!\n");
+                break;
+            }
+        }
+        
+        if (wait_round == 9) {
+            printf("等待超时,仍有连接未关闭\n");
+        }
+    }
+    
+    /* 再次检查连接状态 */
+    printf("检查连接清理状态...\n");
+    for (uint32_t i = 0; i < g_stress_test.connection_count; i++) {
+        if (g_stress_test.connections[i].handle) {
+            printf("警告: 连接 %u 仍然存在,强制清理\n", i);
+            tcp_manager_close(g_stress_test.connections[i].handle);
+            g_stress_test.connections[i].handle = NULL;
+        }
+    }
     
     /* 重置连接状态 */
     for (uint32_t i = 0; i < g_stress_test.connection_count; i++) {
@@ -549,6 +582,16 @@ int tcp_manager_stress_test(const char* host, uint16_t port, uint32_t test_durat
     
     printf("所有连接已关闭\n");
     
+    /* 显示最终统计信息 */
+    tcp_manager_stats_t final_stats;
+    if (tcp_get_manager_stats(&final_stats) == TCP_MANAGER_OK) {
+        printf("最终统计: 总连接=%u, 活跃连接=%u\n", 
+               final_stats.total_connections, final_stats.active_connections);
+        if (final_stats.active_connections > 0) {
+            printf("警告: 仍有 %u 个连接未清理!\n", final_stats.active_connections);
+        }
+    }
+    
     /* 强制清理TCP管理器 */
     printf("清理TCP管理器...\n");
     tcp_simple_manager_deinit();
@@ -636,8 +679,12 @@ int tcp_manager_basic_test(void)
  */
 int tcp_manager_test_init(void)
 {
-    printf("TCP管理器测试模块初始化\n");
-    /* 这里可以添加一些基本的初始化测试 */
+    tcp_manager_result_t result = tcp_simple_manager_init();
+    if (result == TCP_MANAGER_OK) {
+        printf("TCP管理器初始化成功\n");
+    } else {
+        printf("TCP管理器初始化失败: %d\n", result);
+    }
     return 0;
 }
 
index 98431f9..8f44e0d 100644 (file)
@@ -1,18 +1,19 @@
 /**
- * TCP单线程管理器 v1.3 - 最终修复版本
+ * TCP单线程管理器 v1.5 - lwIP API版本
  * 修复内容:
  * 1. 增大线程栈空间:2KB -> 8KB
  * 2. 简化DNS解析逻辑,避免递归调用
  * 3. 增强资源清理,防止内存泄漏
  * 4. 优化错误处理,避免死循环
  * 5. 使用正确的枚举值
- * TCP单线程管理器 v1.4 - 压力测试优化版本
- * 修复内容:
- * 1. 改进DNS解析,支持并发解析
- * 2. 添加发送队列,避免发送阻塞
- * 3. 优化并发连接处理,增加连接间隔
- * 4. 改进错误处理,支持重试机制
- * 5. 增强连接状态管理
+ * 6. 改进DNS解析,支持并发解析
+ * 7. 添加发送队列,避免发送阻塞
+ * 8. 优化并发连接处理,增加连接间隔
+ * 9. 改进错误处理,支持重试机制
+ * 10. 增强连接状态管理
+ * 11. 完全使用lwIP Socket API,移除标准BSD socket依赖
+ * 12. 添加DNS缓存机制,提高连接性能
+ * 13. 强化连接清理逻辑,避免连接泄漏
  */
 
 #include "tcp_simple_manager.h"
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
-#include <sys/select.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include "lwip/sockets.h"
+/* 使用lwIP网络头文件替代标准网络头文件 */
+#include "lwip/sockets.h"  /* 包含lwIP socket API和fd_set等定义 */
 #include "lwip/netdb.h"
 #include "lwip/sys.h"
 #include "lwip/dns.h"
 #include "lwip/ip.h"
 #include "lwip/err.h"
+#include "lwip/inet.h"
 
-/* 重定义lwIP函数,确保使用标准接口 */
+/* 重定义lwIP函数,确保使用lwIP API */
 #ifndef socket
 #define socket lwip_socket
 #define connect lwip_connect
 #define fcntl lwip_fcntl
 #define getsockopt lwip_getsockopt
 #define setsockopt lwip_setsockopt
+#define shutdown lwip_shutdown
+#define bind lwip_bind
+#define listen lwip_listen
+#define accept lwip_accept
+// #define inet_aton lwip_inet_aton
+// #define inet_ntoa lwip_inet_ntoa
 #endif
 
+/* 使用lwIP的常量定义 */
 #ifndef MSG_DONTWAIT
 #define MSG_DONTWAIT 0x40
 #endif
 
+#ifndef SHUT_RDWR
+#define SHUT_RDWR 2
+#endif
+
+#ifndef SOL_SOCKET
+#define SOL_SOCKET 0xfff
+#endif
+
+#ifndef SO_LINGER
+#define SO_LINGER 13
+#endif
+
+#ifndef SO_KEEPALIVE
+#define SO_KEEPALIVE 9
+#endif
+
+#ifndef IPPROTO_TCP
+#define IPPROTO_TCP 6
+#endif
+
+#ifndef TCP_KEEPIDLE
+#define TCP_KEEPIDLE 1
+#endif
+
+#ifndef TCP_KEEPINTVL
+#define TCP_KEEPINTVL 2
+#endif
+
+#ifndef TCP_KEEPCNT
+#define TCP_KEEPCNT 3
+#endif
+
+/* struct linger已经在系统头文件中定义,无需重复定义 */
+
+/* 确保使用lwIP错误代码 */
+#ifdef LWIP_ERRNO_STDINCLUDE
+/* 如果lwIP使用标准errno,则使用lwIP定义 */
+#include "lwip/errno.h"
+#else
+/* 使用lwIP内部错误代码 */
+#ifndef EAGAIN
+#define EAGAIN 11
+#endif
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK EAGAIN
+#endif
+#ifndef EINPROGRESS
+#define EINPROGRESS 115
+#endif
+#endif
+
 /* 优化后的常量定义 */
 #define TCP_RECV_BUFFER_SIZE    1024
 #define TCP_SEND_QUEUE_SIZE     16      /* 每个连接的发送队列大小 */
@@ -85,6 +142,11 @@ static sys_mutex_t g_connections_mutex;
 static tcp_manager_stats_t g_stats;
 static dns_resolve_state_t g_dns_states[TCP_MANAGER_MAX_CONNECTIONS * 2]; /* 增加DNS状态槽位 */
 
+/* DNS缓存全局变量 */
+static dns_cache_entry_t g_dns_cache[DNS_CACHE_MAX_ENTRIES];
+static sys_mutex_t g_dns_cache_mutex;
+static uint32_t g_dns_cache_access_counter = 0;
+
 /* IO线程相关 */
 static bool g_io_thread_running = false;
 static sys_thread_t g_io_thread;
@@ -98,6 +160,14 @@ static int set_socket_nonblocking(int sockfd);
 static int setup_keepalive(int sockfd);
 static void tcp_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg);
 static int sync_dns_resolve(const char* hostname, struct in_addr* addr);
+
+/* DNS缓存函数声明 */
+static void dns_cache_init(void);
+static void dns_cache_deinit(void);
+static bool dns_cache_lookup(const char* hostname, struct in_addr* addr);
+static void dns_cache_add(const char* hostname, const struct in_addr* addr);
+static void dns_cache_cleanup_expired(void);
+static int dns_resolve_with_cache(const char* hostname, struct in_addr* addr);
 static bool add_to_send_queue(tcp_connection_info_t* conn, const uint8_t* data, uint16_t length);
 static bool process_send_queue(tcp_connection_info_t* conn);
 static void reset_connection_retry(tcp_connection_info_t* conn);
@@ -117,7 +187,7 @@ static void tcp_dns_found_callback(const char *name, const ip_addr_t *ipaddr, vo
         dns_state->failed = false;
         dns_state->resolved_ip = *ipaddr;
         printf("DNS解析成功: %s -> %s\n", dns_state->hostname, 
-               inet_ntoa(*(struct in_addr*)&dns_state->resolved_ip.u_addr.ip4));
+        inet_ntoa(*(struct in_addr*)&dns_state->resolved_ip.u_addr.ip4));
     } else {
         dns_state->resolved = false;
         dns_state->failed = true;
@@ -186,15 +256,25 @@ static int sync_dns_resolve(const char* hostname, struct in_addr* addr)
         printf("DNS缓存命中: %s\n", hostname);
     } else if (err == ERR_INPROGRESS) {
         /* DNS查询进行中,等待完成 */
+        printf("DNS查询进行中,等待完成: %s\n", hostname);
         if (sys_arch_sem_wait(&dns_state->dns_sem, TCP_DNS_TIMEOUT_MS) != SYS_ARCH_TIMEOUT) {
             if (dns_state->resolved && !dns_state->failed) {
                 /* DNS解析成功 */
                 memcpy(&addr->s_addr, &dns_state->resolved_ip.u_addr.ip4, 4);
                 result = 0;
+                printf("DNS解析成功完成: %s -> %s\n", hostname, 
+                       inet_ntoa(*(struct in_addr*)&dns_state->resolved_ip.u_addr.ip4));
+            } else if (dns_state->failed) {
+                printf("DNS解析失败完成: %s\n", hostname);
+                result = -1;
             }
         } else {
             printf("DNS解析超时: %s\n", hostname);
+            result = -1;
         }
+    } else {
+        printf("DNS查询启动失败: %s, 错误: %d\n", hostname, err);
+        result = -1;
     }
     
     /* 清理DNS状态 */
@@ -204,6 +284,200 @@ static int sync_dns_resolve(const char* hostname, struct in_addr* addr)
     return result;
 }
 
+/**
+ * @brief 初始化DNS缓存
+ */
+static void dns_cache_init(void)
+{
+    memset(g_dns_cache, 0, sizeof(g_dns_cache));
+    g_dns_cache_access_counter = 0;
+    
+    if (sys_mutex_new(&g_dns_cache_mutex) != ERR_OK) {
+        printf("DNS缓存: 创建互斥量失败\n");
+    }
+    
+    printf("DNS缓存: 初始化完成, 最大条目数=%d, TTL=%ds\n", 
+           DNS_CACHE_MAX_ENTRIES, DNS_CACHE_TTL_MS / 1000);
+}
+
+/**
+ * @brief 清理DNS缓存
+ */
+static void dns_cache_deinit(void)
+{
+    sys_mutex_free(&g_dns_cache_mutex);
+    memset(g_dns_cache, 0, sizeof(g_dns_cache));
+    printf("DNS缓存: 清理完成\n");
+}
+
+/**
+ * @brief 清理过期的DNS缓存条目
+ */
+static void dns_cache_cleanup_expired(void)
+{
+    uint32_t current_time = sys_now();
+    int cleaned_count = 0;
+    
+    for (int i = 0; i < DNS_CACHE_MAX_ENTRIES; i++) {
+        dns_cache_entry_t* entry = &g_dns_cache[i];
+        if (entry->in_use) {
+            if ((current_time - entry->timestamp) > DNS_CACHE_TTL_MS) {
+                printf("DNS缓存: 清理过期条目 %s\n", entry->hostname);
+                memset(entry, 0, sizeof(dns_cache_entry_t));
+                cleaned_count++;
+            }
+        }
+    }
+    
+    if (cleaned_count > 0) {
+        printf("DNS缓存: 清理了 %d 个过期条目\n", cleaned_count);
+    }
+}
+
+/**
+ * @brief 查找DNS缓存
+ * @param hostname 主机名
+ * @param addr 输出IP地址
+ * @return true表示缓存命中
+ */
+static bool dns_cache_lookup(const char* hostname, struct in_addr* addr)
+{
+    if (!hostname || !addr) return false;
+    
+    sys_mutex_lock(&g_dns_cache_mutex);
+    
+    uint32_t current_time = sys_now();
+    
+    for (int i = 0; i < DNS_CACHE_MAX_ENTRIES; i++) {
+        dns_cache_entry_t* entry = &g_dns_cache[i];
+        if (entry->in_use && strcmp(entry->hostname, hostname) == 0) {
+            /* 检查是否过期 */
+            if ((current_time - entry->timestamp) > DNS_CACHE_TTL_MS) {
+                printf("DNS缓存: 条目已过期 %s\n", hostname);
+                memset(entry, 0, sizeof(dns_cache_entry_t));
+                sys_mutex_unlock(&g_dns_cache_mutex);
+                return false;
+            }
+            
+            /* 缓存命中 */
+            *addr = entry->ip_addr;
+            entry->access_count = ++g_dns_cache_access_counter; /* 更新LRU */
+            
+            printf("DNS缓存: 命中 %s -> %s (访问次数: %u)\n", 
+                   hostname, inet_ntoa(*addr), entry->access_count);
+            
+            sys_mutex_unlock(&g_dns_cache_mutex);
+            return true;
+        }
+    }
+    
+    sys_mutex_unlock(&g_dns_cache_mutex);
+    return false;
+}
+
+/**
+ * @brief 添加DNS缓存条目
+ * @param hostname 主机名
+ * @param addr IP地址
+ */
+static void dns_cache_add(const char* hostname, const struct in_addr* addr)
+{
+    if (!hostname || !addr) return;
+    
+    /* 检查主机名长度 */
+    if (strlen(hostname) >= DNS_HOSTNAME_MAX_LEN) {
+        printf("DNS缓存: 主机名过长, 不缓存 %s\n", hostname);
+        return;
+    }
+    
+    sys_mutex_lock(&g_dns_cache_mutex);
+    
+    /* 先查找是否已存在相同的主机名 */
+    for (int i = 0; i < DNS_CACHE_MAX_ENTRIES; i++) {
+        dns_cache_entry_t* entry = &g_dns_cache[i];
+        if (entry->in_use && strcmp(entry->hostname, hostname) == 0) {
+            /* 更新现有条目 */
+            entry->ip_addr = *addr;
+            entry->timestamp = sys_now();
+            entry->access_count = ++g_dns_cache_access_counter;
+            printf("DNS缓存: 更新条目 %s -> %s\n", hostname, inet_ntoa(*addr));
+            sys_mutex_unlock(&g_dns_cache_mutex);
+            return;
+        }
+    }
+    
+    /* 查找空闲槽位 */
+    dns_cache_entry_t* free_entry = NULL;
+    for (int i = 0; i < DNS_CACHE_MAX_ENTRIES; i++) {
+        if (!g_dns_cache[i].in_use) {
+            free_entry = &g_dns_cache[i];
+            break;
+        }
+    }
+    
+    /* 如果没有空闲槽位,使用LRU算法替换最旧的条目 */
+    if (!free_entry) {
+        uint32_t oldest_access = UINT32_MAX;
+        int oldest_index = 0;
+        
+        for (int i = 0; i < DNS_CACHE_MAX_ENTRIES; i++) {
+            if (g_dns_cache[i].access_count < oldest_access) {
+                oldest_access = g_dns_cache[i].access_count;
+                oldest_index = i;
+            }
+        }
+        
+        free_entry = &g_dns_cache[oldest_index];
+        printf("DNS缓存: LRU替换 %s -> %s\n", free_entry->hostname, hostname);
+    }
+    
+    /* 添加新条目 */
+    memset(free_entry, 0, sizeof(dns_cache_entry_t));
+    free_entry->in_use = true;
+    strncpy(free_entry->hostname, hostname, DNS_HOSTNAME_MAX_LEN - 1);
+    free_entry->ip_addr = *addr;
+    free_entry->timestamp = sys_now();
+    free_entry->access_count = ++g_dns_cache_access_counter;
+    
+    printf("DNS缓存: 添加条目 %s -> %s\n", hostname, inet_ntoa(*addr));
+    
+    sys_mutex_unlock(&g_dns_cache_mutex);
+}
+
+/**
+ * @brief 带缓存的DNS解析函数
+ * @param hostname 主机名
+ * @param addr 输出IP地址
+ * @return 0表示成功,-1表示失败
+ */
+static int dns_resolve_with_cache(const char* hostname, struct in_addr* addr)
+{
+    if (!hostname || !addr) return -1;
+    
+    /* 首先检查是否为IP地址 */
+    if (inet_aton(hostname, addr) != 0) {
+        printf("DNS解析: 直接使用IP地址 %s\n", hostname);
+        return 0;
+    }
+    
+    /* 查找缓存 */
+    if (dns_cache_lookup(hostname, addr)) {
+        return 0;
+    }
+    
+    printf("DNS解析: 缓存未命中,进行网络解析 %s\n", hostname);
+    
+    /* 执行实际的DNS解析 */
+    int result = sync_dns_resolve(hostname, addr);
+    
+    if (result == 0) {
+        /* 解析成功,添加到缓存 */
+        dns_cache_add(hostname, addr);
+    }
+    
+    return result;
+}
+
 /**
  * @brief 设置socket为非阻塞模式
  */
@@ -273,11 +547,43 @@ static void cleanup_connection_unsafe(tcp_connection_info_t* conn)
     
     printf("清理连接资源: handle=%p, sockfd=%d\n", conn->handle, conn->sockfd);
     
-    /* 关闭socket */
+    /* 优雅关闭socket */
     if (conn->sockfd >= 0) {
-        shutdown(conn->sockfd, SHUT_RDWR); /* 优雅关闭 */
+        printf("关闭Socket: %d (状态: %d)\n", conn->sockfd, conn->state);
+        
+        /* 首先发送FIN,启动正常的TCP关闭流程 */
+        if (conn->state == TCP_STATE_CONNECTED) {
+            printf("发送FIN,启动TCP关闭流程...\n");
+            shutdown(conn->sockfd, SHUT_WR);  /* 只关闭写端,允许接收FIN-ACK */
+            conn->state = TCP_STATE_CLOSING;
+            
+            /* 给一些时间让TCP完成四次挥手 */
+            for (int i = 0; i < 50; i++) {  /* 最多等待500ms */
+                sys_msleep(10);
+                
+                /* 检查连接是否已经关闭 */
+                int error = 0;
+                socklen_t len = sizeof(error);
+                if (getsockopt(conn->sockfd, SOL_SOCKET, SO_ERROR, &error, &len) == 0) {
+                    if (error != 0) {
+                        printf("TCP连接已关闭,错误码: %d\n", error);
+                        break;
+                    }
+                }
+                
+                /* 尝试读取,检查是否收到FIN */
+                char dummy;
+                int ret = recv(conn->sockfd, &dummy, 1, MSG_DONTWAIT);
+                if (ret == 0) {
+                    printf("收到FIN,TCP连接正常关闭\n");
+                    break;
+                }
+            }
+        }
+        
+        /* 最后关闭socket文件描述符 */
         close(conn->sockfd);
-        printf("Socket已关闭: %d\n", conn->sockfd);
+        printf("Socket文件描述符已关闭: %d\n", conn->sockfd);
     }
     
     /* 清理发送队列 */
@@ -540,6 +846,45 @@ static void tcp_manager_io_thread(void* arg)
             
             switch (conn->state) {
                 case TCP_STATE_CONNECTING:
+                    /* 检查连接是否完成 */
+                    if (conn->sockfd >= 0) {
+                        int error = 0;
+                        socklen_t len = sizeof(error);
+                        if (getsockopt(conn->sockfd, SOL_SOCKET, SO_ERROR, &error, &len) == 0) {
+                            if (error == 0) {
+                                /* 连接成功完成 */
+                                printf("连接完成: handle=%p, sockfd=%d\n", conn->handle, conn->sockfd);
+                                conn->state = TCP_STATE_CONNECTED;
+                                conn->last_activity = sys_now();
+                                g_stats.active_connections++;
+                                
+                                /* 设置Keep-Alive */
+                                setup_keepalive(conn->sockfd);
+                                
+                                /* 调用连接成功回调 */
+                                if (conn->connect_cb) {
+                                    printf("调用连接成功回调: handle=%p\n", conn->handle);
+                                    conn->connect_cb(conn->handle, true);
+                                } else {
+                                    printf("警告: 连接 %p 没有连接回调函数\n", conn->handle);
+                                }
+                                continue;
+                            } else {
+                                printf("连接失败: handle=%p, error=%d\n", conn->handle, error);
+                                if (conn->connect_cb) {
+                                    printf("调用连接失败回调: handle=%p\n", conn->handle);
+                                    conn->connect_cb(conn->handle, false);
+                                }
+                                cleanup_connection_unsafe(conn);
+                                continue;
+                            }
+                        } else {
+                            printf("调试: 连接 %p 的getsockopt失败: %d\n", conn->handle, errno);
+                        }
+                    } else {
+                        printf("调试: 连接 %p 的sockfd为%d\n", conn->handle, conn->sockfd);
+                    }
+                    
                     /* 检查连接超时 */
                     if ((sys_now() - conn->last_activity) > TCP_CONNECT_TIMEOUT_MS) {
                         printf("连接超时: handle=%p\n", conn->handle);
@@ -571,9 +916,42 @@ static void tcp_manager_io_thread(void* arg)
                     break;
                     
                 case TCP_STATE_CLOSING:
-                    /* 等待关闭完成 */
-                    if (conn->sockfd < 0) {
-                        cleanup_connection_unsafe(conn);
+                    /* 正在关闭的连接,监控关闭进度 */
+                    if (conn->sockfd >= 0) {
+                        /* 检查连接是否已经关闭 */
+                        char dummy;
+                        int ret = recv(conn->sockfd, &dummy, 1, MSG_DONTWAIT);
+                        if (ret == 0) {
+                            /* 收到FIN,连接已正常关闭 */
+                            printf("TCP连接已正常关闭: handle=%p\n", conn->handle);
+                            close(conn->sockfd);
+                            conn->sockfd = -1;
+                            conn->state = TCP_STATE_DISCONNECTED;
+                            if (conn->disconnect_cb) {
+                                conn->disconnect_cb(conn->handle);
+                            }
+                            /* 清理连接资源,但不再尝试关闭socket */
+                            memset(conn, 0, sizeof(tcp_connection_info_t));
+                            conn->sockfd = -1;
+                            conn->in_use = false;
+                            printf("连接资源清理完成\n");
+                        } else if (ret < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
+                            /* 连接出错,强制关闭 */
+                            printf("TCP连接关闭异常: handle=%p, errno=%d\n", conn->handle, errno);
+                            close(conn->sockfd);
+                            conn->sockfd = -1;
+                            conn->state = TCP_STATE_ERROR;
+                        }
+                    } else {
+                        /* socket文件描述符已关闭,清理连接记录 */
+                        conn->state = TCP_STATE_DISCONNECTED;
+                        if (conn->disconnect_cb) {
+                            conn->disconnect_cb(conn->handle);
+                        }
+                        memset(conn, 0, sizeof(tcp_connection_info_t));
+                        conn->sockfd = -1;
+                        conn->in_use = false;
+                        printf("连接记录已清理: handle=%p\n", conn->handle);
                     }
                     break;
                     
@@ -635,6 +1013,13 @@ static void tcp_manager_io_thread(void* arg)
             }
         }
         
+        /* 定期清理过期的DNS缓存条目 */
+        static uint32_t last_cache_cleanup = 0;
+        if ((sys_now() - last_cache_cleanup) > 60000) { /* 每60秒清理一次 */
+            dns_cache_cleanup_expired();
+            last_cache_cleanup = sys_now();
+        }
+        
         /* 防止CPU占用过高 */
         if (total_connections == 0) {
             sys_msleep(50);
@@ -669,12 +1054,16 @@ tcp_manager_result_t tcp_simple_manager_init(void)
     /* 初始化DNS状态数组 */
     memset(g_dns_states, 0, sizeof(g_dns_states));
     
+    /* 初始化DNS缓存 */
+    dns_cache_init();
+    
     /* 初始化统计信息 */
     memset(&g_stats, 0, sizeof(g_stats));
     
     /* 创建互斥锁 */
     if (sys_mutex_new(&g_connections_mutex) != ERR_OK) {
         printf("TCP管理器初始化失败: 无法创建互斥锁\n");
+        dns_cache_deinit();
         return TCP_MANAGER_THREAD_ERROR;
     }
     
@@ -733,12 +1122,50 @@ tcp_manager_result_t tcp_simple_manager_deinit(void)
     /* 释放互斥锁 */
     sys_mutex_free(&g_connections_mutex);
     
+    /* 清理DNS缓存 */
+    dns_cache_deinit();
+    
     g_manager_initialized = false;
     printf("TCP管理器反初始化完成\n");
     
     return TCP_MANAGER_OK;
 }
 
+/**
+ * @brief 显示DNS缓存状态
+ */
+void tcp_show_dns_cache(void)
+{
+    sys_mutex_lock(&g_dns_cache_mutex);
+    
+    printf("\n=== DNS缓存状态 ===\n");
+    printf("最大条目数: %d\n", DNS_CACHE_MAX_ENTRIES);
+    printf("缓存TTL: %d秒\n", DNS_CACHE_TTL_MS / 1000);
+    printf("当前时间: %u\n", sys_now());
+    
+    int used_entries = 0;
+    uint32_t current_time = sys_now();
+    
+    for (int i = 0; i < DNS_CACHE_MAX_ENTRIES; i++) {
+        dns_cache_entry_t* entry = &g_dns_cache[i];
+        if (entry->in_use) {
+            used_entries++;
+            uint32_t age = current_time - entry->timestamp;
+            bool expired = (age > DNS_CACHE_TTL_MS);
+            
+            printf("[%02d] %s -> %s (年龄: %us, 访问: %u%s)\n",
+                   i, entry->hostname, inet_ntoa(entry->ip_addr),
+                   age / 1000, entry->access_count,
+                   expired ? " [已过期]" : "");
+        }
+    }
+    
+    printf("使用中的条目: %d/%d\n", used_entries, DNS_CACHE_MAX_ENTRIES);
+    printf("==================\n\n");
+    
+    sys_mutex_unlock(&g_dns_cache_mutex);
+}
+
 /**
  * @brief 连接到指定地址
  */
@@ -785,9 +1212,9 @@ tcp_handle_t tcp_open_url(const char* host, uint16_t port,
     
     sys_mutex_unlock(&g_connections_mutex);
     
-    /* DNS解析 */
+    /* DNS解析(带缓存) */
     struct in_addr addr;
-    if (sync_dns_resolve(host, &addr) < 0) {
+    if (dns_resolve_with_cache(host, &addr) < 0) {
         printf("DNS解析失败: %s\n", host);
         sys_mutex_lock(&g_connections_mutex);
         cleanup_connection_unsafe(conn);
@@ -825,16 +1252,23 @@ tcp_handle_t tcp_open_url(const char* host, uint16_t port,
     }
     
     /* 发起连接 */
+    struct sockaddr_in server_addr;
+    memset(&server_addr, 0, sizeof(server_addr));
+    server_addr.sin_family = AF_INET;
+    server_addr.sin_addr = addr;
+    server_addr.sin_port = htons(port);
+    
     int result = connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
     
     if (result == 0) {
-        /* 连接立即成功 */
+        /* 立即连接成功 */
+        conn->sockfd = sockfd;  /* 关键修复:设置socket文件描述符 */
         conn->state = TCP_STATE_CONNECTED;
         conn->last_activity = sys_now();
         g_stats.total_connections++;
         g_stats.active_connections++;
         
-        printf("连接立即成功: %s:%d, handle=%p\n", host, port, conn->handle);
+        printf("连接立即成功: %s:%d, handle=%p, sockfd=%d\n", host, port, conn->handle, sockfd);
         
         /* 设置Keep-Alive */
         setup_keepalive(sockfd);
@@ -849,12 +1283,13 @@ tcp_handle_t tcp_open_url(const char* host, uint16_t port,
         
     } else if (errno == EINPROGRESS || errno == EAGAIN || errno == EWOULDBLOCK) {
         /* 连接正在进行中 */
+        conn->sockfd = sockfd;  /* 关键修复:设置socket文件描述符 */
         conn->state = TCP_STATE_CONNECTING;
         conn->last_activity = sys_now();
         g_stats.total_connections++;
         g_stats.active_connections++;
         
-        printf("连接进行中: %s:%d, handle=%p\n", host, port, conn->handle);
+        printf("连接进行中: %s:%d, handle=%p, sockfd=%d\n", host, port, conn->handle, sockfd);
         
         sys_mutex_unlock(&g_connections_mutex);
         return conn->handle;
index ffd8f88..9c23969 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <stdint.h>
 #include <stdbool.h>
+#include "lwip/inet.h"  /* for struct in_addr - 使用lwIP版本 */
 
 #ifdef __cplusplus
 extern "C" {
@@ -153,6 +154,20 @@ typedef struct {
     uint32_t errors;
 } tcp_manager_stats_t;
 
+/* DNS缓存配置 */
+#define DNS_CACHE_MAX_ENTRIES   16      /* 最大缓存条目数 */
+#define DNS_CACHE_TTL_MS        300000  /* 缓存有效期: 5分钟 */
+#define DNS_HOSTNAME_MAX_LEN    64      /* 主机名最大长度 */
+
+/* DNS缓存条目结构 */
+typedef struct {
+    bool in_use;                        /* 是否使用中 */
+    char hostname[DNS_HOSTNAME_MAX_LEN]; /* 主机名 */
+    struct in_addr ip_addr;             /* 解析的IP地址 */
+    uint32_t timestamp;                 /* 缓存时间戳 */
+    uint32_t access_count;              /* 访问次数(用于LRU) */
+} dns_cache_entry_t;
+
 /**
  * @brief 初始化TCP管理器
  * 创建IO线程、初始化队列、设置回调等
@@ -223,6 +238,11 @@ tcp_manager_result_t tcp_manager_close(tcp_handle_t handle);
  */
 tcp_connection_state_t tcp_get_connection_state(tcp_handle_t handle);
 
+/**
+ * @brief 显示DNS缓存状态
+ */
+void tcp_show_dns_cache(void);
+
 /**
  * @brief 获取管理器统计信息
  * 
index f1cb0e9..f68f3f4 100644 (file)
@@ -220,6 +220,9 @@ class TCPTestServer:
                 print(f"  平均包大小: {conn_info['bytes_received'] / conn_info['packets_count']:.1f} 字节" if conn_info['packets_count'] > 0 else "  平均包大小: 0 字节")
                 print("-" * 60)
                 
+                # 显示当前连接状态
+                print(f"当前活跃连接数: {self.global_stats['active_connections']}")
+                
                 del self.connections[conn_id]
                 
     def stats_monitor(self):
@@ -234,8 +237,8 @@ class TCPTestServer:
                 avg_throughput = self.global_stats['total_bytes'] / uptime if uptime > 0 else 0
                 
                 print(f"\n=== 服务器总体统计 (运行时间: {uptime:.0f}s) ===")
-                print(f"活跃连接: {self.global_stats['active_connections']}")
-                print(f"总连接数: {self.global_stats['total_connections']}")
+                print(f"当前连接数: {self.global_stats['active_connections']} (活跃)")
+                print(f"历史连接数: {self.global_stats['total_connections']} (累计)")
                 print(f"总包数: {self.global_stats['total_packets']:,}")
                 print(f"总数据量: {self.format_bytes(self.global_stats['total_bytes'])}")
                 print(f"平均吞吐量: {self.format_bytes(avg_throughput)}/s")
@@ -279,11 +282,19 @@ class TCPTestServer:
         avg_throughput = self.global_stats['total_bytes'] / uptime if uptime > 0 else 0
         
         print(f"运行时间: {uptime:.2f} 秒")
-        print(f"总连接数: {self.global_stats['total_connections']}")
+        print(f"剩余连接数: {self.global_stats['active_connections']} (应该为0)")
+        print(f"历史连接数: {self.global_stats['total_connections']} (累计)")
         print(f"总包数: {self.global_stats['total_packets']:,}")
         print(f"总数据量: {self.format_bytes(self.global_stats['total_bytes'])}")
         print(f"平均吞吐量: {self.format_bytes(avg_throughput)}/s")
         print(f"峰值吞吐量: {self.format_bytes(self.global_stats['max_throughput_bps'])}/s")
+        
+        # 检查是否有连接泄漏
+        if self.global_stats['active_connections'] > 0:
+            print(f"⚠️  警告: 仍有 {self.global_stats['active_connections']} 个连接未正常关闭!")
+        else:
+            print("✅ 所有连接已正常关闭")
+            
         print("服务器已关闭。")
 
 def main():