1.前言

最近有一些讨论关于lwIP如何在单机的环境(比如,没有一个多线程的操作系统)使用。

本文的目的就是描述lwIP如何在无多线程操作系统或有多线程操作系统环境中运行

2.lwIP单线程内核

2.1 lwIP内核包含的组件

lwIP的内核包括了IP,ICMP,UDP协议的实现,还包括了对缓存和内存的管理。

当lwIP在一个单线程(不是操作系统)环境中运行只有内核组件是必须的。

你可以加入并运行DHCP、DNS,但它们并不是必须的。你编译代码可以只支持UDP或TCP。

2.2 lwIP内核接口

内核组件可以被看成一个软件库,该软件库提供如下接口:

(1)ip_input(pbuf, netif)

把IP数据包和刚引入数据的网络接口作为参数,并对数据包进行TCP/IP处理。

(2)定时器相关

自从lwIP 1.4.0开始,定时器的相关功能移交给TCP定时器,并且加入了对DNS和DHCP定时器的支持。

你可以使用sys_check_timeouts()并且停止阅读这个命题。在一些老版本中,tcp_tmr()每隔250ms(TCP_TMR_INTERVAL)被调用一次来处理所有与TCP定时器相关的处理比如重新传输。

这些定时器函数只在当你运行TCP时需要。

2.3 单线程举例

由于在单线程环境中,内核函数并不会被阻塞,所以可以不需要sys_arch(操作系统抽象层)的实现(信号量和邮箱函数只保留定义)。

在主循环里将会调用链接层驱动,这将导致ip_input(pbuf,netif)的调用,从而导致IP数据报的处理并调用上层协议的handler,最终调用你的回调函数。

一个简单的单线程主循环系统(lwIP 1.4.0+)如下所示:

while() {
/* poll the driver, get any outstanding frames, alloc memory for them, and
call netif->input, which is actually ip_input() */
poll_driver(netif);
sys_check_timeouts(); /* Handle all system timeouts for all core protocols */
}

注:上面主循环的实现可以通过ping来检测,在incontrib/ports/unix/proj/minimal/里面有一个单线程主循环的实现,你可以自己查看更多的内容。

2.4 系统定时器

在你的裸机系统里你可能有自己的系统定时器,然而你可能想利用lwIP定时器系统来实现你的目的或者处理一些周期性网络任务或延迟相应的网络应用任务。

让我们来假设你有如下函数:

static void myfunction(something *myarg);

你想要该函数过一段时间后再被调用,那么你可以把该函数作为一个参数如下所示:

sys_timeout(APPOPPRIATE_TIME, (sys_timeout_handler) myfunction, myarg);

当你不想要它时,你可以移除该定时器如下所示:

sys_untimeout((sys_timeout_handler) myfunction, myarg);

每次你设置的timeout都是使用系统结构体的元素,因此你要保留足够的空间来满足你的配置。

如果你有足够的好奇(你应该有)来查看opts.h文件,你将会看到如下内容:

/**
* MEMP_NUM_SYS_TIMEOUT: the number of simultaneously active timeouts.
* The default number of timeouts is calculated here for all enabled modules.
* The formula expects settings to be either '0' or '1'.
*/
#ifndef MEMP_NUM_SYS_TIMEOUT
#define MEMP_NUM_SYS_TIMEOUT (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (
*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT)
#endif

你需要在lwipopts.h文件里添加正确的数值。

2.5. 1.4.0先前的版本(TODO)

在一些lwIP的老版本中,一个简单的单线程主循环如下所示:

while() {
if(poll_driver(netif) == PACKET_READY) {
pbuf = get_packet(netif);
ip_input(pbuf, netif);
}
if (clock() - last_arp_time >= ARP_TMR_INTERVAL * CLOCKTICKS_PER_MS)
{
etharp_tmr();
last_arp_time = clock();
}
if(clock() - last_time >= TCP_TMR_INTERVAL * CLOCKTICKS_PER_MS) {
tcp_tmr();
last_time = clock();
}
}

注意:硬件定时器至少要每毫秒滴答(tick)一次,这样CLOCKTICKS_PER_MS才有效。如果你想要使用OS-tick-counter(比如,每10ms增加一次),你要调整代码如下所示:clock() - last_time >= TCP_TMR_INTERVAL / MS_PER_TICK

假如你不只使用TCP/IP和ARP,你需要增加定时器的调用次数。在一个多线程系统里,所有的定时器都在api/tcpip.c中调用,因此这个源文件是一个来检查你是否需要加入更多的定时器(比如,IP_PEASSEMBLY,DHCP,等等)的好地方。提示:在api/tcpip.c和以上例子中,定时器并不会“catch up”,意思是如果有一个定时器延迟了(不管什么原因),那么接下来的定时器滴答(ticks)也会被延迟。

3.lwIP在多线程系统中

lwIP被设计成可以在多线程系统中运行,可以和应用并发运行。

在这种情况下所有TCP/IP的处理都在一个线程中。应用线程可以通过序列API来和TCP/IP线程进行通信。

内部线程间的通信都在文件api_lib.c和api_msg.c中实现。api_lib.c包含了被应用程序使用的函数,api_msg.c实现了TCP/IP协议栈的接口。

还有一个第三文件tcpip.c来处理刚接收到的数据包和定时器事件(在先前有描述)。

当lwIP在一个多线程环境中运行,刚接收到的数据包被函数tcpip_input()(或者被tcpip_ethinput())所处理,该函数的参数与ip_input()函数相同。

这两个函数的差别在于tcpip_input()函数并不会马上处理刚接收到的数据包,它只是将数据包放在一个队列,该数据随后被TCP/IP线程处理。

当在一个多线程系统中运行,定时器事件在tcpip.c中被处理。你可以参考下面编程:

struct netif this_netif;

void init()
{
memset( &my_netif, , sizeof(my_netif));
tcpip_init( ethernet_init_inside_thread, "");
} void ethernet_init_inside_thread( void *parm)
{
struct ethernetif *ethernetif;
struct ip_addr netmask; this_netif.state =NULL;
this_netif.name[] =;
this_netif.name[] =;
this_netif.output = etharp_output;
this_netif.linkoutput = low_level_output;
this_netif.next =NULL;
IP4_ADDR( &netmask, , , , );
netif_add( &this_netif, NULL, &netmask, NULL, NULL, ethernetif_init_low, tcpip_input);
netif_set_default(&this_netif);
this_netif.hwaddr_len = ETHARP_HWADDR_LEN;
this_netif.hwaddr[] = ; // or whatever u like
this_netif.hwaddr[] = ;
this_netif.hwaddr[] = ;
this_netif.hwaddr[] = ;
this_netif.hwaddr[] = ;
this_netif.hwaddr[] = ;
this_netif.mtu = ;
this_netif.flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
dhcp_start(&this_netif);
}

LwIP Application Developers Manual7---lwIP with or without an operating system的更多相关文章

  1. LwIP Application Developers Manual11---Initializing lwIP

    1.前言 2.Initialization for simple lwIP 查看doc/rawapi.txt来获得更多官方信息 #if NO_SYS /* Network interface vari ...

  2. LwIP Application Developers Manual8---Sample lwIP applications

    1.前言 你已经编译lwIP协议栈在你的目标平台上,并且网络驱动正常工作.你可以ping你的设备. 干得好,为你感到骄傲.虽然一个设备可以响应ping,但并不能算一个完整的应用. 现在你可以通过网络接 ...

  3. LwIP Application Developers Manual12---Configuring lwIP

    1.前言 2.LwIP makefiles With minimal features C_SOURCES = \ src/api/err.c \ src/core/init.c \ src/core ...

  4. LwIP Application Developers Manual2---Protocols概览

    1.前言 本文是对LwIP Application Developers Manual的翻译 lwIP是模块化的并支持广泛的协议,这些大部分协议可以被裁减从而减小代码的尺寸 2.协议概览 链路层和网络 ...

  5. LwIP Application Developers Manual1---介绍

    1.前言 本文主要是对LwIP Application Developers Manual的翻译 2.读者(应用开发手册的读者) 谁适合读这份手册 网络应用的开发者 想了解lwIP的网络应用开发者 阅 ...

  6. LwIP Application Developers Manual9---LwIP and multithreading

    1.前言 lwIP的内核并不是线程安全的.如果我们必须在多线程环境里使用lwIP,那么我们必须使用“upper”API层的函数(netconn或sockets).当使用raw API时,你需要自己保护 ...

  7. LwIP Application Developers Manual5---高层协议之DNS

    1.前言 lwIP提供一个基本的DNS客户端(1.3.0后引进),通过使用DNS(Domain Name System)协议来允许应用程序解决主机名到地址的转换. 在文件lwipopts.h里面定义L ...

  8. LwIP Application Developers Manual5---高层协议之DHCP,AUTOIP,SNMP,PPP

    1.前言 本文主要讲述高层协议,包括DHCP 2.DHCP 2.1 从应用的角度看DHCP 你必须确保在编译和链接时使能DHCP,可通过在文件lwipopts.h里面定义LWIP_DHCP选项,该选项 ...

  9. LwIP Application Developers Manual4---传输层之UDP、TCP

    1.前言 本文主要讲解传输层协议UDP TCP 2.UDP 2.1 UDP from an application perspective 2.2 UDP support history in lwI ...

  10. LwIP Application Developers Manual3---链路层和网络层协议之IPV6,ICMP,IGMP

    1.前言 本文主要讲述链路层和网络层的协议IPV6,ICMP 2.IPV6 2.1 IPV6特性 IPv6是IPv4的更新.其最显著的差别在于地址空间由32位转换成128位 2.2 从应用的角度看IP ...

随机推荐

  1. 虚拟机centos无法连接外网时怎么处理

    1. 首先查看service 如果没有启动请启动这2个服务. 2. 在虚拟机那重启网络端口 ifdown ens33 ifup ens33

  2. python如何直接控制鼠标键盘

    一.简介 我们知道在windows下输入:win + r,会弹出下面的窗口,而在下面的窗口出现后我们接着按下esc键,下面的窗口会消失 现在设想我们想在python代码里控制键盘,想通过运行代码-&g ...

  3. Java Web之HTML5

    终于学到Java Web这一章节了,首先来了解一下HTML5的一些新知识点吧,我直接贴出HTML5代码看一下: <!DOCTYPE html> <html lang="en ...

  4. java io系列09之 FileDescriptor总结

    本章对FileDescriptor进行介绍 转载请注明出处:http://www.cnblogs.com/skywang12345/p/io_09.html FileDescriptor 介绍 Fil ...

  5. vs code解决golang开发环境问题 dial tcp 216.239.37.1:443: connectex: A connection attempt failed

    安装插件是出现 如下错误提示, https fetch failed: Get https://golang.org/x/tools/cmd/gorename?go-get=1: dial tcp 2 ...

  6. mysql使用navicat和mysqldump导出数据

    1.navicat 方式一:选中表,右键转储:(含有表结构和数据) 方式二:选择右上角工具,点击数据传输,在这个页面右侧选择数据库,左侧选择文件. 点击下一步,选择导出的表名和各种函数什么的,然后点击 ...

  7. ACM-ICPC 2018 徐州赛区网络预赛 I Characters with Hash(模拟)

    https://nanti.jisuanke.com/t/31461 题意 一个hash规则,每个字母映射成一个两位数,求给的字符串最后的编码位数,要求去除最终结果的前导零 分析 按题意模拟就是了 # ...

  8. 关于REST API设计的文章整理

    1. rest api uri设计的7个准则(1)uri末尾不需要出现斜杠/(2)在uri中使用斜杠/表达层级关系(3)在uri中可以使用连接符-提升可读性(4)在uri中不允许出现下划线字符_(5) ...

  9. Java实现猜数字,附带提示功能。

    很简单的一段代码: package com.changeyd.demo; import java.util.Random;import java.util.Scanner;public class M ...

  10. Gossip

    http://www.cnblogs.com/xingzc/p/6165084.html 敬请期待...