知方号

知方号

lwip15

lwip15

前言

终于到接口层了。

原文:李柱明博客:https://www.cnblogs.com/lizhuming/p/17442931.html

框架描述

前面我们已经学完了,都知道raw接口了,其实也可以直接用,就是麻烦点。

这里NETCONN就是封装了raw接口,让用户使用更加简单。

socket接口是封装NETconn接口的,让用户使用更加标准,方便应用程序移植。

NETCONN的接口框架:

解耦:编写回调函数xxx_tcp()、xxx_udp(),注册到协议栈里面。协议栈通过回调函数告知接口层,当前PCB的状态信息。接口层根据当前PCB的状态信息做相应处理即可。

文件:

api_msg.c​:构建api msg,被netconn调用,发送到内核锁或tcpip内核线程执行指定的回调函数。api_lib.c​:netconn API。sockets.c​:socket套接字接口层,封装netconn接口。供用户使用。

NETCONN重要组成内核回调接口

在raw/callback API编程时,用户编程的方法就是向内核注册各种自定义的回调函数,回调函数是与内核实现交互的唯一方式。

协议栈API NETCONN是基于raw/callback API实现的。

内核通过调用注册到TCP/UDP内核的回调函数,把接收到的数据或可发送数据的事件发送回netconn对应的邮箱中,上层检查这些邮箱即可和内核协议栈交互。

netbuf:数据缓冲

netbuf是应用层描述待发送数据和已接收数据的基本结构。当然,最基本的粒度数据结构还是pbuf。

应用层接收数据:

当协议栈收到数据包后,会将数据封装在一个netbuf​中,并递交给应用层。

应用层发送数据:

TCP:用户只需要提供待发数据的起始地址和长度,内核会根据实际情况封装在合适大小的数据包中。UDP:需要用户自行将数据封装在netbuf​​结构中。

netbuf数据结构:

/** "Network buffer" - contains data and addressing info */struct netbuf { struct pbuf *p, *ptr; /* 包缓冲区。p:pbuf链。ptr:pbuf链中当前pbuf游标。 */ ip_addr_t addr; /* 发送方IP */ u16_t port; /* 发送方端口 */#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY u8_t flags; /* 标志位 */ u16_t toport_chksum; /* 目的端口号。用于checksum */#if LWIP_NETBUF_RECVINFO ip_addr_t toaddr; /* 目的地址 */#endif /* LWIP_NETBUF_RECVINFO */#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */};

netconn:接口数据结构

代表一个连接,TCP或UDP等。

相关文件:api.h

分析完UDP和TCP协议实现后,会分析他们的原生接口udp_xxx()和tcp_xxx()都是互相独立的。

而连接结构netconn就是为了统一这些接口。

netconn控制块:

/** A netconn descriptor */struct netconn { /** type of the netconn (TCP, UDP or RAW) */ enum netconn_type type; /* 连接类型 */ enum netconn_state state; /* netconn当前状态。即是当前netconn被哪些netconn API占用 */ union { struct ip_pcb *ip; /* IP控制块 */ struct tcp_pcb *tcp; /* TCP控制块 */ struct udp_pcb *udp; /* UDP控制块 */ struct raw_pcb *raw; /* TCP控制块 */ } pcb; /* 内核中与连接相关的控制块指针 */ /* 此netconn的最新未报告的异步错误 */ err_t pending_err;#if !LWIP_NETCONN_SEM_PER_THREAD /* 只能每个netconn数据结构占用一个信号量 */ /* 信号量。是对一个API完成两部分线程的同步。如用户调用API,API调用内核API,并等待内核API完成后通过该信号量通知当前API。 */ sys_sem_t op_completed;#endif /* 接收数据的邮箱。数据缓冲队列。 */ sys_mbox_t recvmbox;#if LWIP_TCP /* 用于TCP服务器端。连接请求的缓冲队列。 */ sys_mbox_t acceptmbox;#endif /* LWIP_TCP */#if LWIP_NETCONN_FULLDUPLEX /* 全功率 */ /* mbox的读阻塞线程数。当线程在waiting时closing,需要解除所有线程的阻塞。 */ int mbox_threads_waiting;#endif union { int socket; /* socket */ void *ptr; /* 指针 */ } callback_arg; /* 回调参数 */#if LWIP_SO_SNDTIMEO /* 发送超时 */ /* 等待发送数据超时值,单位ms。 */ s32_t send_timeout;#endif /* LWIP_SO_RCVTIMEO */#if LWIP_SO_RCVTIMEO /* 接收超时 */ /* 等待接收新数据的超时时间,单位ms。 */ u32_t recv_timeout;#endif /* LWIP_SO_RCVTIMEO */#if LWIP_SO_RCVBUF /* 接收缓冲区 */ /* 应用层的接收缓冲区size。限制recvmbox上所有数据的size。 */ int recv_bufsize; /* recvmbox 当前接收到的数据size,用于FIONREAD。 */ int recv_avail;#endif /* LWIP_SO_RCVBUF */#if LWIP_SO_LINGER /* SO_LINGER选项 */ /* < 0: 关闭该功能。 = 0: 立即关闭。发送缓冲区残留有数据时,RST给对端。 > 0: 超时值。单位:秒。超时前尽量把发送缓冲区中的数据发送出去。 */ s16_t linger;#endif /* LWIP_SO_LINGER */ /* 包含

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至lizi9903@foxmail.com举报,一经查实,本站将立刻删除。