struct udp_pcb {
/* Common members of all PCB types */
IP_PCB;
/* Protocol specific PCB members */
struct udp_pcb *next;
u8_t flags;
u16_t local_port, remote_port;
u16_t chksum_len;
void (* recv)(void *arg, struct udp_pcb *pcb, struct pbuf *p,
struct ip_addr *addr, u16_t port);
void *recv_arg;
};
ip_input()--->
udp_input()--->
pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src); //回调
void
udp_recv(struct udp_pcb *pcb,
void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p,
struct ip_addr *addr, u16_t port),
void *recv_arg)
{
/* remember recv() callback and user data */
pcb->recv = recv;
pcb->recv_arg = recv_arg;
}
UDP例子(9000端口----9000端口)
void test_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
{
struct pbuf a;
a = *p;
pcb = pcb;
udp_sendto(pcb,&a,addr,port);
pbuf_free(p);
}
struct udp_pcb *test_udp;
test_udp = udp_new();
udp_bind(test_udp,&ipaddr,9000);
udp_connect(test_udp,IP_ADDR_ANY,9000);
udp_recv(test_udp, test_recv, ðif);
u16_t pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) ---重要函数可用于将UDP接收的数据取出放在自己的定义的数组中
将pbuf中偏移offset开始的len长度内容拷贝到dataptr指向的存储区中
/* ---------- Pbuf options ---------- */
/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */
#define PBUF_POOL_SIZE 30
/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */
#define PBUF_POOL_BUFSIZE 500
例如一个UDP接收默认采用PBUF_POOL固定容量,每个链表长度500字节,链表长度30个
关于LWIP---UDPlwip是一个轻量级的TCP/IP协议栈(Lightweight TCP/IP Stack)实现,最初是瑞士计算机科学学院Adam Dunkels编写的一个应用于无操作系统的嵌入式系统中的TCP/IP协议栈,后来作为一个开源(open source)项目,由一个全球性的团队进行开发和维护。 已实现的部分有: 1. 标准的TCP/IP协议栈实现,包括TCP、UDP、ICMP、IP、ARP、DHCP; ICMP(Internet control message protocol):网络维护和调试。 UDP(User datagram protocol) DHCP(Dynamic host configuration protocol) ARP(Address resolution protocol)
2.非标准Socket接口,lwip提供了一套Socket API,这套API的标准与正常操作系统下的Socket API的形式不是很一致,我们先前已经在这套API上实现了Web Server,已测试在没有Mobile IP环境下工作正常。 下面我们就一个lwip典型的UDP协议工作过程作为对lwip的简单介绍。
UDP发送过程: 1.应用层:绑定UDP套接字 udp_bind()的处理流程图 2.传输层的处理 3.IP层的处理 4.ARP协议的处理 5. 数据链路层的处理
UDP接收过程: 接收过程与发送过程刚好相反,数据报文首先调用ethernet_input()函数到达数据链路层,去掉以太网头部之后如果是ARP报文传给调用arp_input()交给ARP协议处理,如果是IP报文就调用ip_input()进入IP层处理,ip_input()函数中比较数据报文的目的IP地址,如果与某个网络接口的IP地址相同,则接收这个报文,依照IP头部的协议字段,调用各自协议的输入处理函数,本例中将调用udp_input(),在udp_input()中提取数据报文的端口号,然后在已登记的套接字中查找与该端口号符合的UDP接收函数,如果没有找到相应的套接字,调用icmp_output()发送一个ICMP不可达报文,如果找到了,就调用该函数(这个函数就是我们在udp_bind()时传入的其中一个参数)。 udp_input处理流程图: |