• uIP的ARP协议分析


    地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址(MAC)的一个TCP/IP协议。在三层网络层我们确定了IP地址后,信息来到了二层进行再封装,在二层需要MAC地址,这时就通过三层的IP去寻找二层的MAC。
    信息沿着下图的黑线路径进行传播,从高层往低层是不断封包,从低层往高层是不断解包。
    这里写图片描述
    下图是ARP的帧格式
    这里写图片描述
    结构ether_header定义了以太网帧首部;结构arphdr定义了其后的5个字段,其信息用于在任何类型的介质上传送ARP请求和回答;ether_arp结构除了包含arphdr结构外,还包含源主机和目的主机的地址。
    分析一下ARP包头。头两个字节是硬件类型0x0001,接着两个字节是协议类型,即ARP使用的是IP协议代号0x0800。硬件地址长度和协议地址长度分别是6和4。这与ARP报文格式是对应的。后面的2个字节OP指示当前包是请求包还是应答包,对应的值分别是0x0001和0x0002。
    下图是用Wireshark抓取的ARP包,上图是请求包(PC发往uIP),请求时,是向局域网询问,而不是向整个Internet询问,下图是应答包(uIP发往PC),可以注意到的是,请求包是42字节,而应答包是经过填充的60字节。至于原因,其实还没有想清楚。
    这里写图片描述

    这里写图片描述

    下面是uIP的主要结构,是官方提供的主要使用格式,可以将while中的函数封装成一个轮询函数uip_polling(),需要循环起来。uIP在不同的应用中,函数uip_polling()都不需要改,需要改的是宏UIP_APPCALL,在uIP中,使用的都是UIP_APPCALL,若改成自己的函数,就会运行我们的函数啦。
    时钟对于uIP来说是非常重要的,如果缺少了时钟,那么uIP只会ping和arp,TCP和UDP都需要时钟的支持。时钟的完成我们需要用到定时器中断,如果用uCOS的话,就可以把systick中断定时拿来当做uIP时钟。

    //将以下声明放入uip_app.h,然后在uip_conf.h中,加入#include"uip_app.h"
    void tcp_appcall(void);
    #ifndef UIP_APPCALL
      #define UIP_APPCALL tcp_appcall
    #endif
    //uIP初始化
    int i;
    uip_ipaddr_t ipaddr;
    struct timer periodic_timer, arp_timer;
    
    timer_set(&periodic_timer, CLOCK_SECOND / 2);
    timer_set(&arp_timer, CLOCK_SECOND * 10);
    
    tapdev_init();
    uip_init();
    
    uip_ipaddr(ipaddr, 192,168,0,2);
    uip_sethostaddr(ipaddr);
    uip_ipaddr(ipaddr, 192,168,0,1);
    uip_setdraddr(ipaddr);
    uip_ipaddr(ipaddr, 255,255,255,0);
    uip_setnetmask(ipaddr);
    while(1) {
        //从网络设备读取一个IP包,数据长度uip_len在uip.c中定义
        uip_len = tapdev_read();
        if(uip_len > 0) {
            //处理IP数据包(只有校验通过的IP包才会被接收)
            if(BUF->type == htons(UIP_ETHTYPE_IP)){//是否是IP包,这里的类型指的是以太帧结构中的类型,即MAC地址后面的类型
                uip_arp_ipin();//空
                uip_input();//IP包处理,若有需要返回的数据,则存入uip_buf,长度为uip_len,这两个变量是全局变量
                if(uip_len > 0) {
                //目的地址是否在一个局域网,若是,查ARP表;若不是,MAC地址填写默认路由器地址(网关)。
                //查ARP表,若IP在表中,取MAC地址即可;若IP不在表中,将发送ARP包来取代本来要发送的IP包
                    uip_arp_out();
                    tapdev_send();//发送数据到以太网
                }
            }
            else if(BUF->type == htons(UIP_ETHTYPE_ARP)){//是否是ARP包
                //如果收到的ARP为请求,就想自己的信息放入uip_buf并顺便根据请求者的信息更新ARP表;
                //如果是回应包,就更新ARP表
                uip_arp_arpin();
                if(uip_len > 0) {
                    tapdev_send();//发送数据到以太网
                }
            }
        }
        else if(timer_expired(&periodic_timer)) {//定时器定时,可以为0.5s
            timer_reset(&periodic_timer);//复位定时器
            for(i = 0; i < UIP_CONNS; i++) {//轮流处理每个TCP连接
                uip_periodic(i);//处理TCP通信事件,若有需要返回的数据,则存入uip_buf,长度为uip_len,这两个变量是全局变量
                if(uip_len > 0) {
                    uip_arp_out();
                    tapdev_send();
                }
            }
    #if UIP_UDP
            for(i = 0; i < UIP_UDP_CONNS; i++) {//轮流处理每个UDP连接
                uip_udp_periodic(i);//处理UDP通信事件
                if(uip_len > 0) {
                    uip_arp_out();
                    tapdev_send();
                }
            }
    #endif /* UIP_UDP */
            if(timer_expired(&arp_timer)) {//建议为每隔10s调用一次ARP更新
                timer_reset(&arp_timer);
                uip_arp_timer();
            }
        }
    }

    【Reference】http://www.cnblogs.com/laojie4321/archive/2012/04/12/2444187.html

  • 相关阅读:
    JavaScript数组
    JavaScript正则表达式之分组匹配 / 反向引用
    JavaScript函数之作用域 / 作用链域 / 预解析
    JavaScript正则表达式实例汇总
    python+unittets框架
    locust简介
    seleniumselenium各种技巧,滑动,提示框,窗口大小,iframe切换等等
    selenium 定位元素的方式
    jmeter环境配置,配置中文环境,原理-1
    appium环境搭建+真机+获取package和activity来验证是否搭建成功+appium自带的定位元素
  • 原文地址:https://www.cnblogs.com/season-peng/p/6713511.html
Copyright © 2020-2023  润新知