嵌入式软件异步编程:基于回调的lwIP raw API

    xiaoxiao2021-03-25  68

    lwIP提供了两套API,分别是顺序模型的API和基于回调的raw API,raw API可以做到又快又省,即运行速度快,资源消耗少,非常适合嵌入式系统。

    原文:http://blog.csdn.net/ruizeng88/article/details/6577615 原文标题:《lwIP raw API》

    简介

    lwIP提供了两套API:

    底层的基于回调(callback)的raw API高层的顺序模型的API(类似BSD socket)

    顺序模型的API为普通的顺序程序提供使用协议栈的API,和BSD风格的API很相似,也是基于阻塞的open-read-write-close模式。鉴于TCP/IP协议栈本身就基于时间的。所以TCP/IP代码和应用程序的代码必须在不同的线程中。

    而raw API可以让应用程序和TCP/IP协议栈代码结合的更紧密。程序的执行也是基于事件的,使用回调函数的机制。这种方式TCP/IP代码和应用代码运行在同一个线程中。

    实际上,顺序模型的API也是基于raw API实现的。

    回调

    程序的执行是基于回调函数的,回调函数从传入的参数获取当前连接的状态。为回调函数设置连接状态参数的函数如下:

    void tcp_arg(struct tcp_pcb *pcb, void *arg);

    pcb是当前TCP连接的控制块,arg是将会传给回调函数的参数。

    建立TCP连接

    TCP连接建立的方法和BSD socket很相似,通过tcp_new函数可以创建一个新的TCP标识(在raw API中是PCB这个结构——protocol control block)。PCB可以设置成监听一个连接或者明确地连接到一个主机。

    struct tcp_pcb *tcp_new(void);

    创建一个新的PCB,如果返回NULL表示创建失败。

    err_t tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) ;

    将pcb绑定到一个本地IP地址+端口。IP地址可以设置成IP_ADDR_ANY以绑定到所有本地IP地址。如果其他连接已经绑定到该端口则会返回ERR_USE,否则返回ERR_OK。

    struct tcp_pcb *tcp_listen(struct tcp_pcb *pcb);

    让pcb进入监听状态。当一个新的连接建立时,由tcp_accept指定的回调函数将被调用。该函数会返回一个新的pcb,作为参数传递的那个pcb会被释放。失败时返回NULL,此时参数的pcb将不会被释放。

    struct tcp_pcb *tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog);

    类似于tcp_listen,但是会限制在等待连接的队列中的连接的数量(不能超过backlog),需要在lwipopts.h中将TCP_LISTEN_BACKLOG设置为1.

    void tcp_accepted(struct tcp_pcb *pcb);

    告诉lwIP新的连接已经被接受,通常在接受回调函数中调用,通知lwIP做可以允许更多的连接请求。

    void tcp_accept(struct tcp_pcb *pcb, err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err));

    指明当新的连接建立时执行的回调函数。

    err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port, err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err));

    将pcb连接到远程的主机并发送SYN段打开连接。 tcp_connect()函数是立即返回的,它不会等待连接真的被建立,当连接真正建立时它会调用第四个参数connected函数,如果连接不能成功建立则connect函数的参数err会设置成对应的错误值。如果没有足够的空间将SYN请求入队列该函数会返回ERR_MEM,否则成功的话会返回ERR_OK。

    发送数据

    TCP数据是通过tcp_write函数发送的:

    err_t tcp_write(struct tcp_pcb *pcb, void *dataptr, u16_t len, u8_t copy);

    将dataptr指向的数据送到发送队列。len是发送数据的长度,copy参数表示是否允许数据拷贝。当发送的数据超过当前发送缓冲区或者发送队列的长度超过最大限制,该函数会返回ERR_MEM。发送队列中可用的字节数可以用tcp_sndbuf()函数获取。这个函数合适的用法是,发送不大于tcp_sndbuf()长度的字节数,如果返回ERR_MEM,程序等待发送队列数据空间足够后继续调用。

    void tcp_sent(struct tcp_pcb *pcb, err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len));

    指定数据被成功发送后(收到远程主机的响应信息)应该执行的回调函数。len参数表示上次ACK中确定的字节数。

    接收数据

    TCP数据的接收是基于回调的。程序指定当新的数据到来是应该执行的回调函数。

    void tcp_recv(struct tcp_pcb *pcb, err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err));

    设置接收到数据时应该调用的回调函数。如果pbuf==NULL则证明远程主机已经关闭连接。如果没有错误,并且回调函数将返回ERR_OK时,必须首先释放pbuf。否则不要释放pbuf以便lwIP保存。

    void tcp_recved(struct tcp_pcb *pcb, u16_t len);

    当程序接收完毕数据时调用,len是接收的数据长度。

    关闭连接

    err_t tcp_close(struct tcp_pcb *pcb); void tcp_abort(struct tcp_pcb *pcb);

    两个函数的不同在于,第二个函数永远不会出错~

    转载请注明原文地址: https://ju.6miu.com/read-40967.html

    最新回复(0)