【LwIP - UDP】- 实现UDP通信

目录

 

基于LwIP实现UDP通信

1 什么是UDP

2 基于raw/callback API的UDP

3 raw/callback API UDP的绑定、连接和发送


基于LwIP实现UDP通信

1 什么是UDP

UDP,即用户数据包协议,属于TCP/IP 中的传输层。同样,TCP,即传输控制协议,也是属于TCP/IP传输层。这两者区别在此处不加以解释,本文主要讲解如何通过LwIP实现UDP传输。

UDP在传输数据之前不需建立连接。远端收到UDP用户数据报,是不需要给出任何应答。虽然UDP是一种不可靠的交付,但在某些情况下UDP却是一种有效的传输方式。

 

2 基于raw/callback API的UDP

raw/callback API提供了多个UDP相关的接口,如下所示:

struct udp_pcb * udp_new        (void); // 动态分配一个UDP控制块
void             udp_remove     (struct udp_pcb *pcb); // 释放一个UDP控制块
err_t            udp_bind       (struct udp_pcb *pcb, ip_addr_t *ipaddr, 
                                 u16_t port); // UDP控制块绑定本地IP和本地端口
err_t            udp_connect    (struct udp_pcb *pcb, ip_addr_t *ipaddr,
                                 u16_t port); // UDP控制块连接远端IP和远端端口
void             udp_disconnect (struct udp_pcb *pcb); // 取消UDP控制块与远端socket的连接关系
void             udp_recv       (struct udp_pcb *pcb, udp_recv_fn recv,
                                 void *recv_arg); // UDP回调
err_t            udp_sendto_if  (struct udp_pcb *pcb, struct pbuf *p,
                                 ip_addr_t *dst_ip, u16_t dst_port,
                                 struct netif *netif); // 指定网卡及远端socket发送UDP用户数据报
err_t            udp_sendto     (struct udp_pcb *pcb, struct pbuf *p,
                                 ip_addr_t *dst_ip, u16_t dst_port); // 指定远端socket发送UDP用户数据报
err_t            udp_send       (struct udp_pcb *pcb, struct pbuf *p); // 根据UDP控制块连接的远端socket发送UDP用户数据报

// 以下几个用于UDP校验,当UDP不使用校验,则校验默认为0。当使用校验,如果校验值为0,则改成0xFFFF。
#if LWIP_CHECKSUM_ON_COPY
err_t            udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p,
                                 ip_addr_t *dst_ip, u16_t dst_port,
                                 struct netif *netif, u8_t have_chksum,
                                 u16_t chksum);
err_t            udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p,
                                 ip_addr_t *dst_ip, u16_t dst_port,
                                 u8_t have_chksum, u16_t chksum);
err_t            udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p,
                                 u8_t have_chksum, u16_t chksum);
#endif /* LWIP_CHECKSUM_ON_COPY */

#define          udp_flags(pcb) ((pcb)->flags) // 
#define          udp_setflags(pcb, f)  ((pcb)->flags = (f))

/* The following functions are the lower layer interface to UDP. */
void             udp_input      (struct pbuf *p, struct netif *inp); // UDP输入,获取数据

void             udp_init       (void);    // UDP初始化,主要做UDP的内存池和内存栈初始化

1.1 udp_init

与UDP内存池和内存栈初始化相关。

1.2 udp_input

处理UDP用户数据报相关。

1.3 udp_new和udp_remove

udp_new: 动态分配一个UDP控制块,该控制块记录本地socket和远端socket等信息。

udp_remove: 释放UDP控制块

至于剩下的接口,上面的注释已经解释很清楚了。以下主要分析udp_bind、udp_connect和几个发送接口。

3 raw/callback API UDP的绑定、连接和发送

udp_connect和几个发送接口,在没有开发者没有为UDP控制块绑定本地socket时,这几个接口默认会调用udp_bind,为UDP控制块绑定socket,其中端口是动态分配的。

udp_conncet与udp_bind的区别在于UDP控制块的标志是否被设置为连接态(UDP_FLAGS_CONNECTED),因此我们可以对这个进行划分:

  • 连接态: udp_conncet
  • 非连接态: udp_bind

udp_conncet用有特定远端socket,而udp_bind用于任何远端socket。也就是说,只要发送给开发板的数据报文的远端socket与开发板本地socket一致,开发板都会正常接收该UDP数据报。如果开发板有UDP控制块指定了远端socket,也有无指定的远端socket控制块,则会优先匹配有远端socket的控制块。当然,收到的UDP数据报的源socket不与开发板任何一个UDP,只要本地socket匹配都会处理该数据报。当然,这种现象是不可能的,毕竟一个UDP控制块对应一个唯一的端口。总的来说,udp_conncet只处理指定远端socket的UDP数据报,而udp_bind可以处理任何远端socket的UDP数据报(前提该数据报符合本地socket)。

下列给出上述两种情况的例子:

(1) 指定远程socket例子

void udp_demo_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p,
    ip_addr_t *addr, u16_t port)
{
	struct ip_addr my_ipaddr;
	unsigned char *temp = (unsigned char *)addr;
	IP4_ADDR(&my_ipaddr, temp[0], temp[1], temp[2], temp[3]); // 保存源IP
	udp_sendto(pcb, p, &my_ipaddr, port); // 将报文返回给原主机
	pbuf_free(p);
}

u8 udp_demo(void)
{
	struct udp_pcb *pcb;
	ip_addr_t remote_ip;
	pcb	= udp_new();
	if(pcb == NULL)	 // 申请失败
	{
		return 1;
	}else
	{
		IP4_ADDR(&remote_ip,192, 168, 1, 100);
		if(udp_connect(pcb, &remote_ip, 8080) == ERR_OK ) // 连接到指定的IP地址和端口
		{
			udp_recv(pcb, udp_demo_callback, NULL); // 注册报文处理回调				
			printf("local_port %d\r\n", pcb->local_port);
		}else
			return 1;
	}
	return 0;
}

(2) 不指定远程socket例子

void udp_demo_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p,
    ip_addr_t *addr, u16_t port)
{
	struct ip_addr my_ipaddr;
	unsigned char *temp = (unsigned char *)addr;
	IP4_ADDR(&my_ipaddr, temp[0], temp[1], temp[2], temp[3]); // 保存源IP
	udp_sendto(pcb, p, &my_ipaddr, port); // 将报文返回给原主机
	pbuf_free(p);
}

u8 udp_demo(void)
{
	struct udp_pcb *pcb;
	ip_addr_t remote_ip;
	pcb	= udp_new();
	if(pcb == NULL)	 // 申请失败
	{
		return 1;
	}else
	{
 
		if(udp_bind(pcb, IP_ADDR_ANY, 8080) == ERR_OK ) // 为本地IP绑定端口,IP_ADDR_ANY为0,其实说明使用本地IP地址,推荐优先使用。因为DHCP情况下,我们是无法事先知道IP的。
		{
			udp_recv(pcb, udp_demo_callback, NULL);     // 注册报文处理回调				
			printf("local_port %d\r\n", pcb->local_port);
		}else
			return 1;
	}
	return 0;
}
  • 8
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: STM32CubeIDE是ST公司推出的一款开发工具,用于开发STM32系列微控制器。 LWIP(Lightweight IP)是一个轻量级的开源TCP/IP协议栈,适用于嵌入式系统。 在STM32CubeIDE中使用LWIP库进行UDP通信,可以通过以下步骤实现: 1. 首先,需要创建一个新的STM32项目,并选择合适的型号和外设。在项目配置中,选择LWIP库,并启用UDP协议。 2. 在代码中,需要进行一些配置。首先,在"LwIP SYS"组件中,设置正确的IP地址和子网掩码。然后,在"LwIP UDP"组件中,配置正确的端口号,以及设置允许UDP广播和多播。 3. 接下来,需要创建UDP通信的客户端和服务器端。客户端需要创建一个socket,并设置目标IP地址和端口号。然后,可以使用lwip_sendto函数发送UDP数据包。 4. 服务器端需要创建一个socket,并绑定到本地IP地址和端口号。然后,使用lwip_recvfrom函数接收来自客户端的UDP数据包。 5. 在接收到UDP数据包后,可以对数据进行处理,并根据需要进行相应的操作。例如,可以将数据发送到其他设备,或者执行相应的程序逻辑。 通过以上步骤,就可以在STM32CubeIDE中使用LWIP实现UDP通信。在实际应用中,根据具体需求,可以进一步优化代码和功能,以实现更复杂的通信功能。 ### 回答2: STM32CubeIDE是STMicroelectronics推出的一款面向STM32微控制器的集成开发环境。它集成了STM32CubeMX配置工具和TrueSTUDIO IDE,可以方便地进行STM32微控制器的开发和调试。 lwIP是一个轻量级的嵌入式TCP/IP协议栈,它为嵌入式系统提供了网络通信功能。在STM32CubeIDE中,可以通过lwIP协议栈实现UDP通信。 在使用STM32CubeIDE进行lwIP UDP通信时,首先需要通过STM32CubeMX配置工具进行初始化设置。在配置工具中,可以选择启用lwIP协议栈,并设置相关的网络参数,如IP地址、子网掩码、网关等。同时,还可以选择启用UDP协议,并设置相关的端口号。 配置完成后,生成代码并导入到STM32CubeIDE中。接下来,可以在工程中编写相关的代码实现UDP通信功能。首先,需要创建一个UDP Socket,并设置相关的参数,如IP地址和端口号。然后,可以使用lwIP提供的API函数发送和接收UDP数据包。 发送UDP数据包时,可以使用lwIP提供的函数lwip_sendto(),将要发送的数据和目标地址通过参数传入。接收UDP数据包时,可以使用lwIP提供的函数lwip_recvfrom(),指定接收数据的缓冲区和缓冲区大小,并将接收到的数据和发送方的地址存储在传入的参数中。 通过以上的步骤,就可以在STM32CubeIDE中实现lwIP UDP通信。用户可以根据实际需求进行相关的配置和代码编写,以实现网络通信功能。需要注意的是,在使用lwIP协议栈时,需要了解其相关的API函数和使用方法,以确保正确实现所需功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值