标签:term 使用 添加 dm9000 技术分享 socket 小型 intern pac
1. SylixOS网络协议栈基本介绍SylixOS网络协议栈使用目前非常流行的嵌入式TCP/IP协议栈lwip。lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。lwip特点是对RAM与ROM的占用非常少,只需十几KB的RAM和40K左右的ROM就可以运行,非常适合嵌入式系统使用。
本文将会介绍基于dm9000网卡的数据包收发流程。
pbuf是lwip中用来表示数据包的结构体,数据包在协议栈各层的流动也是通过pbuf来实现的,基本结构如程序清单 2.1所示。
程序清单2.1
/* Main packet buffer struct */struct pbuf {2 struct pbuf *next; /* 下一个pbuf结构 */ void *payload; /* 实际数据起始地址 */ u16_t tot_len; /* pbuf链总长度 */ u16_t len; /* 当前pbuf长度 */ u8_t type_internal; /* pbuf类型 */ u8_t flags;LWIP_PBUF_REF_T ref; /* 初始化为1,pbuf->next指向自己时ref加1 */ u8_t if_idx;void *if_out; };
pbuf的字段type_internal表示pbuf类型,lwip中有四种类型PBUF_RAM、PBUF_ROM、PBUF_REF和PBUF_POOL:
1) PBUF_RAM类型的pbuf结构是一块很大的内存空间,内存首部是pbuf结构,实际数据接在后面,发送数据时常使用这种类型。如图 2.1所示;
图 2.1 PBUF_RAM类型的pbuf结构
2) PBUF_POOL类型是由多个pbuf结构组合而成,使用next字段将这些pbuf结构连接起来。其中tot_len表示此节点和next之后所有节点的长度和,len表示当前节点的数据长度。接收数据时常使用这类型的pbuf结构。如图 2.2所示;
图 2.2 BUF_POOL类型的pbuf结构
3) PBUF_REF与PBUF_ROM类似,pbuf结构是单独的一块内存空间,而data是另一块内存,二者并不相连,如图 2.3所示;
图 2.3 BUF_REF和PBUF_ROM类型的pbuf结构
Lwip协议栈使用pbuf结构在各层之间传递数据包,通过移动payload指针的方式在数据中添加报文头和剔除报文头,从而实现“零拷贝”机制,提高报文处理效率。
UDP数据包的发送是通过sendto()发起的(其他接口类似),整体实现流程如下:
1) 通过文件描述符fd获取文件结构并提取lwipfd,再通过lwipfd从socket表中获取socket结构。Socket结构中包含了此udp链接中的connect信息;
2) 使用netbuf_alloc()创建netbuf结构,这其中包含了pbuf结构。向这个结构导入需要发送的数据;
3) Netbuf结构最终会传入udp_send()或udp_sendto(),这其中会通过ip_route()确定最终需要发送的网卡结构netif;
4) Udp_sendto_if_src()添加udp包头;
5) If_output_if_src()添加IP包头;
6) 根据网卡结构netif获取发送接口netdev_netif_linkoutput(),最终调用网卡发送函数dm9000_transmit();
发送流程图如图 3.1所示;
图 3.1 发送流程图
数据包接收包括两个部分。首先网卡获取一个数据包并使用中断通知系统,系统解析这个数据包放入缓冲队列中。再由应用层调用接口recv()或recvfrom()获取这个数据包。
1) 系统在初始化时会注册网卡中断,处理函数为dm9000IntIsr()。当接收到一个数据包时会执行中断处理,中断处理内容很简短,仅添加一个接收处理函数dm9000_receive()到任务队列中,数据包主要在接受处理函数中被处理,减少了中断开销;
2) 在dm9000_receive()中首先会创建一个POOL类型的pbuf结构,再调用驱动接口priv->inblk()从网卡中提取报文放入pbuf结构中,执行tcpip_input()处理这个数据包;
3)通过消息队列发送数据到网络线程“t_netproto”,使用一个单独的线程处理此数据包;
4) 进入线程后执行ip4_input()进行网络层处理,提取出运输层数据再通过udp_input()进行udp数据包处理;
5) 根据ip与port找到对应的udp链接信息即udp_pcb结构,提取pcb中对应的接收处理函数pcb->recv()即recv_udp()和链接结构connect,recv_udp()中会将此数据包发送到此udp链接的消息队列中,等待用户层提取;
网卡中断接收流程如图 4.1所示;
图 4.1 网卡中断接收流程
1) 过文件描述符fd获取文件结构,并提取lwipfd。再通过lwipfd从socket表中获取socket结构。Socket结构中包含了此udp链接中的connect信息;
2) 根据connect信息获取对应UDP链接的接收消息队列,并通过调用netconn_recv_data()从消息队列中获取一条报文;
recvfrom()处理流程如图 4.2所示;
图 4.2 recvfrom()处理流程
标签:term 使用 添加 dm9000 技术分享 socket 小型 intern pac
原文地址:http://blog.51cto.com/7199226/2150125