以太网驱动优化,TCP客户端进行优化
This commit is contained in:
278
app/main.c
278
app/main.c
@ -11,6 +11,9 @@
|
||||
#include <string.h>
|
||||
#include "lwip/prot/ip4.h"
|
||||
|
||||
/* Utility macros */
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
/* Network Interface */
|
||||
struct netif gnetif;
|
||||
osal_sem_t sem_ip_ready = NULL;
|
||||
@ -166,14 +169,190 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* TCP Client Configuration */
|
||||
#define TCP_CLIENT_AUTH_USERNAME "admin"
|
||||
#define TCP_CLIENT_AUTH_PASSWORD "password123"
|
||||
#define TCP_CLIENT_MAX_RECONNECT_DELAY 10000 // 最大重连延迟 10 秒
|
||||
#define TCP_CLIENT_INIT_RECONNECT_DELAY 1000 // 初始重连延迟 1 秒
|
||||
#define TCP_CLIENT_HEARTBEAT_INTERVAL 500 // 心跳间隔 500ms
|
||||
#define TCP_CLIENT_AUTH_TIMEOUT 3000 // 认证超时 3 秒
|
||||
#define TCP_CLIENT_CONNECT_TIMEOUT 5000 // 连接超时 5 秒
|
||||
|
||||
/* Helper function: Check if authentication response is successful */
|
||||
static int is_auth_success(const char *response)
|
||||
{
|
||||
if (!response)
|
||||
return 0;
|
||||
|
||||
// 移除末尾的换行符和空格
|
||||
char *p = (char *)response;
|
||||
while (*p && (*p == ' ' || *p == '\n' || *p == '\r')) p++;
|
||||
char *end = p + strlen(p) - 1;
|
||||
while (end > p && (*end == ' ' || *end == '\n' || *end == '\r')) end--;
|
||||
*(end + 1) = '\0';
|
||||
|
||||
// 转换为小写进行比较
|
||||
char lower_data[128];
|
||||
for (int i = 0; p[i]; i++) {
|
||||
lower_data[i] = tolower(p[i]);
|
||||
}
|
||||
lower_data[strlen(p)] = '\0';
|
||||
|
||||
osal_log_i("Processed auth response: '%s'", p);
|
||||
osal_log_i("Lowercase auth response: '%s'", lower_data);
|
||||
|
||||
/* Check if authentication was successful */
|
||||
if (strstr(lower_data, "ok") != NULL ||
|
||||
strstr(lower_data, "success") != NULL ||
|
||||
strstr(lower_data, "auth_success") != NULL)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Helper function: Create and configure socket */
|
||||
static int create_and_configure_socket(void)
|
||||
{
|
||||
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0)
|
||||
{
|
||||
osal_log_e("Socket creation error: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set non-blocking mode */
|
||||
int flags = fcntl(sock, F_GETFL, 0);
|
||||
if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0)
|
||||
{
|
||||
osal_log_e("Failed to set non-blocking mode: %d", errno);
|
||||
closesocket(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set socket options for better performance */
|
||||
int keepalive = 1;
|
||||
int keepidle = 60;
|
||||
int keepintvl = 10;
|
||||
int keepcnt = 3;
|
||||
|
||||
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive));
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof(keepidle));
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepintvl, sizeof(keepintvl));
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(keepcnt));
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
/* Helper function: Connect to server with timeout */
|
||||
static int connect_to_server(int sock, struct sockaddr_in *server_addr)
|
||||
{
|
||||
int ret = connect(sock, (struct sockaddr *)server_addr, sizeof(struct sockaddr));
|
||||
if (ret == -1 && errno != EINPROGRESS)
|
||||
{
|
||||
osal_log_e("Connect failed: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Use select to wait for connection completion */
|
||||
fd_set wset;
|
||||
struct timeval tv;
|
||||
FD_ZERO(&wset);
|
||||
FD_SET(sock, &wset);
|
||||
tv.tv_sec = TCP_CLIENT_CONNECT_TIMEOUT / 1000;
|
||||
tv.tv_usec = (TCP_CLIENT_CONNECT_TIMEOUT % 1000) * 1000;
|
||||
|
||||
if (select(sock + 1, NULL, &wset, NULL, &tv) > 0)
|
||||
{
|
||||
int error = 0;
|
||||
socklen_t len = sizeof(error);
|
||||
getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len);
|
||||
if (error != 0)
|
||||
{
|
||||
osal_log_e("Connect failed: %d", error);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
osal_log_e("Connect timeout");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Helper function: Send authentication and wait for response */
|
||||
static int authenticate_server(int sock)
|
||||
{
|
||||
/* Send authentication information */
|
||||
char auth_data[64];
|
||||
snprintf(auth_data, sizeof(auth_data), "AUTH %s %s\n", TCP_CLIENT_AUTH_USERNAME, TCP_CLIENT_AUTH_PASSWORD);
|
||||
|
||||
if (send(sock, auth_data, strlen(auth_data), 0) < 0)
|
||||
{
|
||||
osal_log_e("Failed to send authentication: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
osal_log_i("Sent authentication: %s", auth_data);
|
||||
|
||||
/* Wait for authentication response */
|
||||
char recv_data[128];
|
||||
fd_set rset;
|
||||
struct timeval tv;
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(sock, &rset);
|
||||
tv.tv_sec = TCP_CLIENT_AUTH_TIMEOUT / 1000;
|
||||
tv.tv_usec = (TCP_CLIENT_AUTH_TIMEOUT % 1000) * 1000;
|
||||
|
||||
if (select(sock + 1, &rset, NULL, NULL, &tv) > 0)
|
||||
{
|
||||
int bytes_received = recv(sock, recv_data, sizeof(recv_data) - 1, 0);
|
||||
if (bytes_received > 0)
|
||||
{
|
||||
recv_data[bytes_received] = '\0';
|
||||
osal_log_i("Authentication response: '%s'", recv_data);
|
||||
|
||||
if (is_auth_success(recv_data))
|
||||
{
|
||||
osal_log_i("Authentication successful!");
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
osal_log_e("Authentication failed: %s", recv_data);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (bytes_received == 0)
|
||||
{
|
||||
osal_log_w("Connection closed by server during authentication");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
osal_log_e("Recv error during authentication: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
osal_log_w("No authentication response received");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* TCP Client Thread */
|
||||
static void tcp_client_entry(void *parameter)
|
||||
{
|
||||
int sock = -1;
|
||||
struct sockaddr_in server_addr;
|
||||
char *send_data = "Hello from RT-Thread Nano TCP Client\n";
|
||||
char recv_data[128];
|
||||
int bytes_received;
|
||||
int reconnect_count = 0;
|
||||
int reconnect_delay = TCP_CLIENT_INIT_RECONNECT_DELAY;
|
||||
|
||||
/* Wait for IP address ready */
|
||||
if (osal_sem_take(sem_ip_ready, OSAL_WAIT_FOREVER) != OSAL_OK)
|
||||
@ -184,6 +363,12 @@ static void tcp_client_entry(void *parameter)
|
||||
|
||||
osal_log_i("TCP Client Starting...");
|
||||
|
||||
/* Prepare server address */
|
||||
server_addr.sin_family = AF_INET;
|
||||
server_addr.sin_port = htons(SERVER_PORT);
|
||||
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP_ADDR);
|
||||
memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Check Link Status */
|
||||
@ -193,66 +378,49 @@ static void tcp_client_entry(void *parameter)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Create socket */
|
||||
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||
/* Create and configure socket */
|
||||
sock = create_and_configure_socket();
|
||||
if (sock < 0)
|
||||
{
|
||||
osal_log_e("Socket error");
|
||||
osal_thread_mdelay(1000);
|
||||
osal_log_e("Failed to create socket, reconnecting in %d ms...", reconnect_delay);
|
||||
osal_thread_mdelay(reconnect_delay);
|
||||
// 指数退避重连
|
||||
reconnect_count++;
|
||||
reconnect_delay = MIN(reconnect_delay * 2, TCP_CLIENT_MAX_RECONNECT_DELAY);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Set non-blocking mode */
|
||||
int flags = fcntl(sock, F_GETFL, 0);
|
||||
fcntl(sock, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
server_addr.sin_family = AF_INET;
|
||||
server_addr.sin_port = htons(SERVER_PORT);
|
||||
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP_ADDR);
|
||||
memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
|
||||
|
||||
osal_log_i("Connecting to server %s:%d...", SERVER_IP_ADDR, SERVER_PORT);
|
||||
|
||||
int ret = connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
|
||||
if (ret == -1 && errno != EINPROGRESS)
|
||||
/* Connect to server */
|
||||
if (connect_to_server(sock, &server_addr) < 0)
|
||||
{
|
||||
osal_log_e("Connect failed");
|
||||
closesocket(sock);
|
||||
osal_thread_mdelay(2000);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Use select to wait for connection completion */
|
||||
fd_set wset;
|
||||
struct timeval tv;
|
||||
FD_ZERO(&wset);
|
||||
FD_SET(sock, &wset);
|
||||
tv.tv_sec = 5;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
if (select(sock + 1, NULL, &wset, NULL, &tv) > 0)
|
||||
{
|
||||
int error = 0;
|
||||
socklen_t len = sizeof(error);
|
||||
getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len);
|
||||
if (error != 0)
|
||||
{
|
||||
osal_log_e("Connect failed: %d", error);
|
||||
closesocket(sock);
|
||||
osal_thread_mdelay(2000);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
osal_log_e("Connect timeout");
|
||||
closesocket(sock);
|
||||
osal_log_e("Connection failed, reconnecting in %d ms...", reconnect_delay);
|
||||
osal_thread_mdelay(reconnect_delay);
|
||||
// 指数退避重连
|
||||
reconnect_count++;
|
||||
reconnect_delay = MIN(reconnect_delay * 2, TCP_CLIENT_MAX_RECONNECT_DELAY);
|
||||
continue;
|
||||
}
|
||||
|
||||
osal_log_i("Connected to server!");
|
||||
|
||||
/* Send greeting */
|
||||
send(sock, send_data, strlen(send_data), 0);
|
||||
/* Authenticate with server */
|
||||
if (!authenticate_server(sock))
|
||||
{
|
||||
osal_log_e("Authentication failed, reconnecting in %d ms...", reconnect_delay);
|
||||
closesocket(sock);
|
||||
osal_thread_mdelay(reconnect_delay);
|
||||
// 指数退避重连
|
||||
reconnect_count++;
|
||||
reconnect_delay = MIN(reconnect_delay * 2, TCP_CLIENT_MAX_RECONNECT_DELAY);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 认证成功,重置重连计数器和延迟
|
||||
reconnect_count = 0;
|
||||
reconnect_delay = TCP_CLIENT_INIT_RECONNECT_DELAY;
|
||||
|
||||
while (1)
|
||||
{
|
||||
@ -262,7 +430,7 @@ static void tcp_client_entry(void *parameter)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Send heartbeat every 1 second */
|
||||
/* Send heartbeat */
|
||||
if (send(sock, "Heartbeat", 9, 0) < 0) {
|
||||
if (errno != EWOULDBLOCK) {
|
||||
osal_log_e("Send error: %d", errno);
|
||||
@ -270,11 +438,13 @@ static void tcp_client_entry(void *parameter)
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for data with timeout */
|
||||
fd_set rset;
|
||||
struct timeval tv;
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(sock, &rset);
|
||||
tv.tv_sec = 1; /* Check periodically */
|
||||
tv.tv_usec = 0;
|
||||
tv.tv_sec = TCP_CLIENT_HEARTBEAT_INTERVAL / 1000;
|
||||
tv.tv_usec = (TCP_CLIENT_HEARTBEAT_INTERVAL % 1000) * 1000;
|
||||
|
||||
int n = select(sock + 1, &rset, NULL, NULL, &tv);
|
||||
if (n > 0) {
|
||||
@ -304,7 +474,11 @@ static void tcp_client_entry(void *parameter)
|
||||
}
|
||||
|
||||
closesocket(sock);
|
||||
osal_thread_mdelay(2000);
|
||||
osal_log_i("Connection closed, reconnecting in %d ms...", reconnect_delay);
|
||||
osal_thread_mdelay(reconnect_delay);
|
||||
// 指数退避重连
|
||||
reconnect_count++;
|
||||
reconnect_delay = MIN(reconnect_delay * 2, TCP_CLIENT_MAX_RECONNECT_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user