RAW接口的UDP实验-STM32H767

1 UDP协议报文结构

2 UDP数据递交流程

用户发送数据为例:

(1)申请一个pbuf。(pbuf游走于应用层、传输层、网络层)。

struct pbuf {
  struct pbuf *next;          // 指向链表中的下一个pbuf
  void *payload;              // 指向数据缓冲区的指针
  u16_t len;                  // 缓冲区的长度
  u16_t tot_len;              // 整个数据包的总长度(如果pbuf是链表的一部分)
  // ... 可能还有其他字段
};

(2)拷贝(把用户数据拷贝到pbuf的数据区)。

(3)调用RAW相关接口将pbuf递交给传输层。

(4)在传输层设置UDP相关字段,递交给网络层。

(5)在网络层添加IP的首部。

3 UDP控制块结构

struct udp_pcb {
  IP_PCB; /* 通用IP控制块 */
  struct udp_pcb *next; /* 下一个节点的指针,用于构成控制块链表 */
  u8_t flags; /* 控制块状态 */
  u16_t local_port, remote_port; /* 本地/远程端口号 */
  udp_recv_fn recv;/* 处理网络接收数据的回调 */
  void *recv_arg; /* 用户自定义参数,接收回调入参 */
#if LWIP_MULTICAST_TX_OPTIONS
#if LWIP_IPV4
  /** outgoing network interface for multicast packets, by IPv4 address (if not 'any') */
  ip4_addr_t mcast_ip4;
#endif /* LWIP_IPV4 */
  /** outgoing network interface for multicast packets, by interface index (if nonzero) */
  u8_t mcast_ifindex;
  /** TTL for outgoing multicast packets */
  u8_t mcast_ttl;
#endif /* LWIP_MULTICAST_TX_OPTIONS */

#if LWIP_UDPLITE
  /** used for UDP_LITE only */
  u16_t chksum_len_rx, chksum_len_tx;
#endif /* LWIP_UDPLITE */
};

LWIP支持多个UDP连接,所以用next指针将这些连接的端口连起来管理。

flags:连接状态、非连接状态

udp_input函数:获取pbuf的UDP的首部,然后遍历UDP的控制块链表(单向链表),判断报文的端口与链表中某个控制块的本地端口是否一致,如果一致,就会将pbuf递交给这个控制块,该控制块将pbuf递交给回调函数处理。

4 UDP控制块原理

链接:多个UDP控制块构建一个单向的链表;

回调函数:每一个控制块都管理一个接受回调函数(此函数可以相同,可以不同);

端口:LWIP内核根据端口号查找控制块;

描述:每一个控制块用来描述各自网络的的信息(一个控制块代表一个UDP连接)。

5 RAW接口的UDP相关函数

函数解释

udp_new

新建一个UDP的PCB控制块
udp_remove将PCB控制块从链表中删除
udp_bind为UDP的PCB控制块绑定一个本地IP地址和端口号
udp_connect连接到指定IP地址主机的指定端口
udp_disconnect断开连接,将控制块设置为非连接状态
udp_send通过有一个PCB控制块发送数据
udp_recv创建的回调函数

6 (RAW)UDP连接配置流程

(1)udp_new 创建一个UDP控制块 ; //描述当前UDP的端口、IP地址等

(2)udp_connect设置目标IP地址和插入UDP PCB链表 ;//发送给谁

(3)udp_bind绑定本地IP地址和端口;//LWIP内核根据端口号把数据发至那个UDP控制块

(4)udp_recv注册接收回调函数;//接受回调函数自行编写(需要参考相关例程)

(5)udp_send发送函数;//网络搭建完成后,收发数据

7 udp代码

建立.c文件,添加代码。


#include "ip_addr.h"
#include "ip4_addr.h"
#include "err.h"
#include "udp.h"
#include "stdio.h"
#include "udp_client.h"
#include "string.h"
#include "pbuf.h"
#define UDP_REMOTE_PORT 7
#define UDP_LOCAL_PORT 7
/*配置UDP客户端,这里需要知道服务器的地址*/
static struct udp_pcb *upcb_client;
char *pdata = "udp test\r\n";
uint8_t recv_flag = 0;
void udp_client_init()
{
  ip_addr_t serverIP;
  err_t err;
  IP4_ADDR(&serverIP,192,168,2,87); /* 绑定服务器的地址 */
  
  /* 本地端口 */
  upcb_client->local_port = UDP_LOCAL_PORT;
  /* 创建udp控制块 */
  upcb_client = udp_new();
  if(upcb_client != NULL)
  {
    printf("udp 控制块创建成功\r\n");
    /* 连接指定ip和端口*/
    err = udp_connect(upcb_client,&serverIP,UDP_REMOTE_PORT);
    if(err == ERR_OK)
    {
      printf("udp_connect连接远程IP、端口成功\r\n");
      /* 绑定本地IP地址和端口号 */
      err = udp_bind(upcb_client,IP_ADDR_ANY,UDP_LOCAL_PORT);
      if(err == ERR_OK)
      {
        printf("udp_bind成功\r\n");
        /* 注册接收回调函数 */
        udp_recv(upcb_client,udp_client_receive_callback,NULL);
        printf("注册就接受回调函数成功\r\n");
        udp_client_send(pdata);
      }
    }
    else
    {
      udp_remove(upcb_client);
      printf("connect udp pcb faild\r\n");
    }
  }
}
u8_t group[100] = {0};
void udp_client_receive_callback(void *arg,struct udp_pcb *pcb,struct pbuf *p,const ip_addr_t *addr, u16_t port)
{
  int i ;
  /* 数据回传 */
//  udp_send(pcb, p);
  
  /* 打印端口 */
  printf("server ip:%d.%d.%d.%d port:%d\r\n", (addr->addr) & 0xff, ((addr->addr)>>8) & 0xff,((addr->addr)>>16) & 0xff,(addr->addr)>>24,port);
  /* 打印接收到的数据 */
  if(p  != NULL)
  {
    struct pbuf *ptemp = p;
  
    while(ptemp != NULL)
    {
      for(i = 0; i< ptemp->len;i++)
      {
        printf("%c",*((char *)ptemp->payload +i));
      }
     
      ptemp = ptemp->next;
    }
    printf("\r\n");
  }
  pbuf_free(p);
}
void udp_client_send(char *pdata)
{
  struct pbuf *p;
  
  /* 分配缓冲区空间 */
  p = pbuf_alloc(PBUF_TRANSPORT,strlen(pdata),PBUF_POOL);
  
  if(p != NULL)
  {
    /* 填充缓冲区数据 */
    pbuf_take(p,pdata,strlen(pdata));
    
    /* 发送udp数据包 */
    udp_send(upcb_client,p);
    
    /* 释放缓冲区 */
    pbuf_free(p);
  }
}

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值