LwIP的TCP客户端先于服务端启动情况下,无法正常连接服务器端的解决办法

本文探讨了在特定应用场景下,使用LwIP协议栈的客户端如何解决服务器端后启动导致的连接问题。通过定时检查TCP连接状态并发送ARP请求包,确保客户端能够在服务器端随机上电的情况下成功建立连接。

在某项目的应用场景下,使用LwIP协议栈的板卡作为客户端。通常,客户端启动后,会主动执行两个初始步骤:
A.首先发送一次ARP请求包,其目的IP地址为服务器端的IP地址;
B.接着执行TCP客户端初始化函数,尝试进行三次握手流程。

服务器端的启动存在两种情况:
情况1:服务器端先于客户端启动
在该情况下,服务器端会立即响应客户端执行的初始步骤A、B,客户端将正常连接将服务器端;
情况2:服务器端后于客户端启动,或服务器端在TCP连接正常的情况下突然断电再上电;
在该情况下,服务器端后于客户端启动,由于客户端不再执行上述两个步骤A、B,则客户端将永远无法连接上服务器端。

项目应用场景下正常使用流程是作为客户端的板卡会优先启动,服务端是根据实时需求随机开关电。因此应用场景属于情况2。

因此,对于情况2板卡客户端需要额外定时执行两个步骤:
步骤1:
查询当前TCP连接状态,若未连接则执行TCP客户端初始化函数尝试重新连接;
步骤2:
由于服务器端可能后于客户端上电,且上电后并不会主动定时发送包含自身MAC地址的ARP响应包,所以需要客户端节点主动周期发送ARP请求包,该包中请求的目的地址就是服务器端的IP地址。

通过上述两个步骤,即可保证在服务器端后上电且不会主动发送自身MAC地址信息的条件下,实现客户端在服务器端随机上电的情况下正常连接上服务器端。

### Windows平台CLion配置UDP服务端 在Windows平台下使用CLion开发UDP服务端,需要配置CMakeLists.txt文件,并引入Windows Socket API(Winsock)以实现UDP通信。Winsock提供了用于网络编程的API接口,允许开发者创建基于TCP/IP和UDP协议的网络应用程序[^1]。 #### CMakeLists.txt配置示例 ```cmake cmake_minimum_required(VERSION 3.20) project(UDPServer VERSION 1.0 LANGUAGES C) set(CMAKE_C_STANDARD 11) add_executable(UDPServer main.c) # 链接Winsock库 target_link_libraries(UDPServer PRIVATE ws2_32) ``` 该配置启用了C11标准,并链接了Windows平台下的Winsock库 `ws2_32`,以便在程序中使用 `winsock2.h` 提供的函数。 #### UDP服务端代码示例 ```c #include <winsock2.h> #include <ws2tcpip.h> #include <stdio.h> #pragma comment(lib, "ws2_32.lib") #define SERVER_PORT 8888 #define BUFFER_SIZE 1024 int main() { WSADATA wsaData; SOCKET serverSocket; struct sockaddr_in serverAddr, clientAddr; int clientAddrLen = sizeof(clientAddr); char buffer[BUFFER_SIZE]; // 初始化Winsock if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { printf("WSAStartup failed.\n"); return -1; } // 创建UDP socket serverSocket = socket(AF_INET, SOCK_DGRAM, 0); if (serverSocket == INVALID_SOCKET) { printf("Socket creation failed.\n"); WSACleanup(); return -1; } // 设置服务器地址结构 serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = INADDR_ANY; serverAddr.sin_port = htons(SERVER_PORT); // 绑定socket if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) { printf("Bind failed.\n"); closesocket(serverSocket); WSACleanup(); return -1; } printf("UDP Server is listening on port %d...\n", SERVER_PORT); while (1) { int recvLen = recvfrom(serverSocket, buffer, BUFFER_SIZE, 0, (struct sockaddr*)&clientAddr, &clientAddrLen); if (recvLen > 0) { buffer[recvLen] = '\0'; printf("Received from client: %s\n", buffer); // 回送数据 sendto(serverSocket, buffer, recvLen, 0, (struct sockaddr*)&clientAddr, clientAddrLen); } } closesocket(serverSocket); WSACleanup(); return 0; } ``` 上述代码实现了基本的UDP服务端功能,包括创建Socket、绑定端口、接收和回送数据。程序持续监听客户端发送的数据,并将其原样返回。 ### STM32F407平台使用LwIP实现UDP客户端 在STM32F407平台上使用LwIP协议栈实现UDP客户端通信,需先完成LwIP的移植和网络接口初始化。LwIP是一个轻量级TCP/IP协议栈,适用于嵌入式系统[^2]。其UDP通信流程主要包括创建UDP控制块、绑定本地端口、设置接收回调函数以及发送数据。 #### LwIP UDP客户端代码示例 ```c #include "lwip/udp.h" #include "lwip/inet.h" #include "lwip/sys.h" #define SERVER_IP "192.168.1.100" // Windows PC的IP地址 #define SERVER_PORT 8888 // UDP服务端端口 #define CLIENT_PORT 9999 // 本地UDP端口 static struct udp_pcb *client_pcb; // 接收回调函数 void udp_receive_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) { if (p != NULL) { char *data = (char *)p->payload; printf("Received from server: %s\n", data); pbuf_free(p); } } void udp_client_init(void) { ip_addr_t server_ip; // 创建UDP控制块 client_pcb = udp_new(); if (client_pcb == NULL) { printf("Failed to create UDP PCB.\n"); return; } // 绑定本地端口 udp_bind(client_pcb, IP_ADDR_ANY, CLIENT_PORT); // 设置接收回调 udp_recv(client_pcb, udp_receive_callback, NULL); // 解析服务器IP地址 inet_aton(SERVER_IP, &server_ip); // 发送数据 const char *msg = "Hello from STM32"; struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, strlen(msg), PBUF_RAM); if (p != NULL) { memcpy(p->payload, msg, strlen(msg)); udp_sendto(client_pcb, p, &server_ip, SERVER_PORT); pbuf_free(p); } } ``` 该代码实现了LwIP UDP客户端的初始化、绑定本地端口、设置接收回调函数以及向服务端发送数据的功能。通过 `udp_sendto` 向指定的IP地址和端口发送消息,并通过 `udp_recv` 注册回调函数接收来自服务端的响应。 ### 数据交互流程说明 1. STM32F407端通过LwIP的UDP接口发送数据到Windows端的指定端口(如8888)。 2. Windows端的UDP服务端接收到数据后,解析内容并回送相同数据。 3. STM32F407端通过注册的接收回调函数处理回送数据,并可进一步处理或显示。 整个通信过程基于UDP协议,无需建立连接,适用于低延迟、低复杂度的嵌入式通信场景。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weekman93

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值