STM32 裸机 LWIP RAW接口 TCP客户端和服务端,以及UDP收发实现
RAW接口
RAW/Callback API 是 LwIP 的一大特色, 在没有操作系统支持的裸机环境中,只能使用这种 API 进行开发;此文章基于野火LWIP教程记录使用方法;使用CubeMX生成LWIP项目,1分钟就可实现TCP、UDP通信;很方便。
关于网线热插拔:我使用CubeMX生成的LWIP裸机项目中发现,网线热插拔在MX_LWIP_Process();已经做了相关处理。直接在轮询中调用即可。
/*** ----------------------------------------------------------------------* Function given to help user to continue LwIP Initialization* Up to user to complete or change this function ...* Up to user to call this function in main.c in while (1) of main(void)*-----------------------------------------------------------------------* Read a received packet from the Ethernet buffers* Send it to the lwIP stack for handling* Handle timeouts if LWIP_TIMERS is set and without RTOS* Handle the llink status if LWIP_NETIF_LINK_CALLBACK is set and without RTOS*/
void MX_LWIP_Process(void)
{
/* USER CODE BEGIN 4_1 */
/* USER CODE END 4_1 */ethernetif_input(&gnetif);/* USER CODE BEGIN 4_2 */
/* USER CODE END 4_2 *//* Handle timeouts */sys_check_timeouts();Ethernet_Link_Periodic_Handle(&gnetif); //检测网线连接状态/* USER CODE BEGIN 4_3 */
/* USER CODE END 4_3 */
}
使用方法,MAIN函数部分。
/* Initialize all configured peripherals */MX_GPIO_Init();MX_LWIP_Init();/* USER CODE BEGIN 2 */TCP_Client_Init(); //TCP客户端TCP_Server_Init(); //TCP服务端UDP_Echo_Init(); //UDP通信/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){if(tick_1ms){MX_LWIP_Process();/* USER CODE END WHILE *//* USER CODE BEGIN 3 */tick_1ms = false;}}
TCP 客户端
#include "tcpclient.h"
#include "lwip/netif.h"
#include "lwip/ip.h"
#include "lwip/tcp.h"
#include "lwip/init.h"
#include "netif/etharp.h"
#include "lwip/udp.h"
#include "lwip/pbuf.h"
#include <stdio.h>
#include <string.h>#define TCP_CLIENT_PORT 5001
void TCP_Client_Init(void);static struct tcp_pcb *client_pcb = NULL;static void client_err(void *arg, err_t err)
{printf("connect error! closed by core!!\n");printf("try to connect to server again!!\n");//连接失败的时候释放TCP控制块的内存tcp_close(client_pcb); //重新连接TCP_Client_Init();
}static err_t client_send(void *arg, struct tcp_pcb *tpcb)
{uint8_t send_buf[]= "This is a TCP Client test...\n";//发送数据到服务器tcp_write(tpcb, send_buf, sizeof(send_buf), 1); return ERR_OK;
}static err_t client_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{if (p != NULL) { /* 接收数据*/tcp_recved(tpcb, p->tot_len);/* 返回接收到的数据*/ tcp_write(tpcb, p->payload, p->tot_len, 1);memset(p->payload, 0 , p->tot_len);pbuf_free(p);} else if (err == ERR_OK) {//服务器断开连接printf("server has been disconnected!\n");tcp_close(tpcb);//重新连接TCP_Client_Init();}return ERR_OK;
}static err_t client_connected(void *arg, struct tcp_pcb *pcb, err_t err)
{printf("connected ok!\n");//注册一个周期性回调函数tcp_poll(pcb,client_send,2);//注册一个接收函数tcp_recv(pcb,client_recv);return ERR_OK;
}void TCP_Client_Init(void)
{ ip4_addr_t server_ip;/* 创建一个TCP控制块 */client_pcb = tcp_new(); IP4_ADDR(&server_ip, DEST_IP_ADDR0,DEST_IP_ADDR1,DEST_IP_ADDR2,DEST_IP_ADDR3);printf("client start connect!\n");//开始连接tcp_connect(client_pcb, &server_ip, TCP_CLIENT_PORT, client_connected); //注册异常处理tcp_err(client_pcb, client_err);
}
TCP服务端
#include "tcpserver.h"
#include "lwip/netif.h"
#include "lwip/ip.h"
#include "lwip/tcp.h"
#include "lwip/init.h"
#include "netif/etharp.h"
#include "lwip/udp.h"
#include "lwip/pbuf.h"
#include <stdio.h>
#include <string.h>#define TCP_Server_PORT 5001
void TCP_Server_Init(void);static err_t tcpecho_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{if (p != NULL) { /* 更新窗口*/tcp_recved(tpcb, p->tot_len);/* 返回接收到的数据*/ tcp_write(tpcb, p->payload, p->tot_len, 1);memset(p->payload, 0 , p->tot_len);pbuf_free(p);} else if (err == ERR_OK) {return tcp_close(tpcb);}return ERR_OK;
}static err_t tcpecho_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{ tcp_recv(newpcb, tcpecho_recv);return ERR_OK;
}void TCP_Server_Init(void)
{struct tcp_pcb *pcb = NULL; /* 创建一个TCP控制块 */pcb = tcp_new(); /* 绑定TCP控制块 */tcp_bind(pcb, IP_ADDR_ANY, TCP_Server_PORT ); /* 进入监听状态 */pcb = tcp_listen(pcb); /* 处理连接 */ tcp_accept(pcb, tcpecho_accept);
}
UDP通信
搞不懂,UDP是无连接通信,不区分服务器和客户端;但是总有人分客户端和服务端。
#include "udpecho.h"
#include "lwip/netif.h"
#include "lwip/ip.h"
#include "lwip/tcp.h"
#include "lwip/init.h"
#include "netif/etharp.h"
#include "lwip/udp.h"
#include "lwip/pbuf.h"
#include <stdio.h>
#include <string.h> #define UDP_ECHO_PORT 5001
void UDP_Echo_Init(void);static void udp_demo_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
{struct pbuf *q = NULL;const char* reply = "This is reply!\n";if(arg){printf("%s",(char *)arg);}pbuf_free(p);q = pbuf_alloc(PBUF_TRANSPORT, strlen(reply)+1, PBUF_RAM);if(!q){printf("out of PBUF_RAM\n");return;}memset(q->payload, 0 , q->len);memcpy(q->payload, reply, strlen(reply));udp_sendto(upcb, q, addr, port);pbuf_free(q);
}static char * st_buffer= "We get a data\n";
void UDP_Echo_Init(void)
{struct udp_pcb *udpecho_pcb;/* 新建一个控制块*/ udpecho_pcb = udp_new(); /* 绑定端口号 */udp_bind(udpecho_pcb, IP_ADDR_ANY, UDP_ECHO_PORT);/* 注册接收数据回调函数 */udp_recv(udpecho_pcb, udp_demo_callback, (void *)st_buffer);
}