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);
}