lwip搭建零配置网络

关于零配置网络

任何一个设备要接入网络中,必须得有IP地址、子网掩码、网关IP地址等信息。嵌入式设备为了方便生产,一般会将这些信息都固定,在设备运行前再根据具体环境对设备进行配置,灵活性大大降低,体验更是渣到不行。而苹果设备易用性的其中一点体现就是,当设备接入一个网络时,不需要做任何的配置,就可以访问。

那苹果设备是如何做到的?

原因就是苹果的设备都使用一项名为Bonjour的技术。这个名字装过iTunes的土豪应该都见过,iTunes附带这个组建,因此装上iTunes的PC也可以很方便的访问苹果设备了。

Bonjour是零配置网络的一个实现,是开源的哦,另一个开源的实现叫avahi。零配置网络,英文全称Zero Configuration Networking,简称Zeroconf。实现零配置网络需要做到以下几点:

  • Allocate addresses without a DHCP server
    在传统网络环境下,设备的IP地址通过两种方式获取,一种是静态配置,通过手工方式为设备指定一个IP地址,一种是动态配置,设备通过DHCP服务器获得动态的IP地址。在有DHCP服务器的网络下,自然可以免除配置,但是在无中心服务器的网络环境下,无法提供DHCP服务,这时候如何解决自动获取IP的问题?
    在IPV6环境下,IPV6协议本身就提供了设备自指定IP地址的能力,所以是直接支持了。
    在IPV4环境下,可以使用链路本地地址(Link-local address)。

  • Translate between names and IP addresses without a DNS server
    在传统网络环境下,名称和IP地址的对应关系是通过DNS服务解析的。在没有中心服务器的网络环境中,没有DNS服务器提供域名解析服务,这时候又该如何解决名称解析的问题?
    Bonjour使用的是叫mDNS的解决方案,mDNS——全称Multicast DNS。

  • Find services without a directory server
    在前面,自动获取IP和名字转IP的问题都解决了。但是还是没能实现一个零配置的网络,因为我不知道设备提供了什么服务,还得手动去配置。所以,最后要解决的就是如何知道网络中的设备提供了哪些服务!!!
    解决方案是DNS Service Discovery (DNS-SD)。

前面提到了两个开源的实现,都满足了上述3点。其中Bonjour有在MT7687上的移植,在SDK中可以找到,没看懂多少……………………

还好,lwIP 2.xx版本提供了mDNS,真的省了不少事。

lwIP提供的mDNS

首先要注意的是,lwIP(V2.1.2)提供的mDNS没有完全实现规范中的所有特性!!!
下面是没有实现的特性:

  • Tiebreaking for simultaneous probing
  • Sending goodbye messages (zero ttl) - shutdown, DHCP lease about to expire, DHCP turned off...
  • Checking that source address of unicast requests are on the same network
  • Limiting multicast responses to 1 per second per resource record
  • Fragmenting replies if required
  • Handling multi-packet known answers
  • Individual known answer detection for all local IPv6 addresses
  • Dynamic size of outgoing packet

虽然没有完全实现规范中的特性,但是看了下V2.1.2以来的更新日志,对MDNS有不少优化的地方,后面应该会更完善的。

使用前准备

1、在lwipopts.h设置LWIP_MDNS_RESPONDER = 1,使能这个特性;
2、定义单个网卡能提供的最大服务个数,MDNS_MAX_SERVICES,默认值是1
3、MDNS需要一个PCB,所以MEMP_NUM_UDP_PCB增加1;
4、MDNS在网卡需要个入口点,所以LWIP_NUM_NETIF_CLIENT_DATA增加1;
5、IPv4下需要设置LWIP_IGMP = 1,最好也设置LWIP_AUTOIP = 1;IPv6下需要设置LWIP_IPV6_MLD = 1;(MDNS支持在IPv4 only, v6 only, 和 v4+v6下使用)
6、为了减少动态内存分配,MDNS代码的运行块放在堆中,最多可能使用1K的大小;

MDNS的使用

注意:LWIP_AUTOIP只有在网络中不存在DHCP Server时才起作用,为了适配两种场景,配置同时支持DHCPAUTOIP!!!

/*
   ------------------------------------
   ---------- AUTOIP options ----------
   ------------------------------------
*/
#define LWIP_DHCP                       1

#define LWIP_AUTOIP                     1

#define LWIP_DHCP_AUTOIP_COOP           1
#define LWIP_DHCP_AUTOIP_COOP_TRIES     5  // 默认是9,调小可以在DHCP失败后更快的切换到AutoIP

/*
   ---------------------------------
   ---------- MDNS options ----------
   ---------------------------------
*/
#define LWIP_MDNS_RESPONDER             1

#define MDNS_MAX_SERVICES               1

#define LWIP_NUM_NETIF_CLIENT_DATA      1
/* Announce IP settings have changed on netif. Call this in your callback registered by [netif_set_status_callback()](group__netif.html#gadc8787b23ac0ee023979cbadf87813d4). No need to call this function when LWIP_NETIF_EXT_STATUS_CALLBACK==1, this handled automatically for you.
 */
#define LWIP_NETIF_EXT_STATUS_CALLBACK  1

直接上代码

const char hostname[] = "NUC472HI8AE";

static void srv_txt(struct mdns_service *service, void *txt_userdata)
{
    err_enum_t res;

    res = mdns_resp_add_service_txtitem(service, "path=/", 6);
    LWIP_ERROR("mdns add service txt failed\n", (res == ERR_OK), return);
}

static void vWebTask( void *pvParameters )
{
    tcpip_init(NULL, NULL);
    
    netif_add(&netif, NULL, NULL, NULL, NULL, ethernetif_init, tcpip_input);
    
    netif_set_default(&netif);

    if (netif_is_link_up(&netif))
    {
        /* When the netif is fully configured this function must be called */
        netif_set_up(&netif);
    }
    else
    {
        /* When the netif link is down this function must be called */
        netif_set_down(&netif);
    }
  
    NVIC_SetPriority(EMAC_TX_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1);
    NVIC_EnableIRQ(EMAC_TX_IRQn);
    NVIC_SetPriority(EMAC_RX_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1);
    NVIC_EnableIRQ(EMAC_RX_IRQn);

#if LWIP_DHCP
  err_t err;

  err = dhcp_start(&netif);
  if (err == ERR_OK)
    log_i("lwip dhcp init success...\n\n");
  else
    log_e("lwip dhcp init fail...\n\n");

#endif

    http_server_netconn_init();

    mdns_resp_init();
    
    mdns_resp_add_netif(&netif, hostname, 3600);
    
    mdns_resp_add_service(&netif, "myweb", "_http", DNSSD_PROTO_TCP, 80, 3600, srv_txt, NULL);
    
    vTaskSuspend( NULL );

}

编译后下载到板子运行,从下图可以看到,192.168.1.159这个地址提供了一个http服务
lwip搭建零配置网络_第1张图片

使用wireshark抓包如下,为了方便查看只过滤192.168.1.159这个地址,从下图可以看出,设备在获取到IP后即广播了自己的服务信息。
lwip搭建零配置网络_第2张图片
访问该服务

尝试在windows 7下用chrome访问NUC472HI8AE.local:80,不成功,在ubuntu上用firefox倒是成功了,可能是windows 7不支持mdns的原因。

lwip搭建零配置网络_第3张图片

遗憾

V2.1.2版本没有提供服务搜寻接口,所以无法在设备上去主动搜寻网络中的服务,下一版会解决这个,只能期待快点发布了。

你可能感兴趣的:(lwip搭建零配置网络)