22227|43

1672

帖子

0

TA的资源

裸片初长成(初级)

楼主
 

程序蒙太奇——Stellaris开发板网络部分小记 (1) [复制链接]

喜欢看电影和影评的同学,一定听说过“蒙太奇”这个术语。蒙太奇(montage)来自法文,大致意思就是,把几件并行发生的事情,剪辑成片段,穿插着表现出来。格里菲斯导演的《党同伐异》中,导演就巧妙地把时空相距甚远的不同活动剪辑在一起,开创了蒙太奇手法的滥觞,如下面的情节:男主角被判处了死刑,即将被押赴刑场处决。女主角拿到了国王的特赦令,飞马赶到刑场在最后时刻救下了男主角。电影中将这两件并行发生的事情,剪切成片段,轮番在银幕上展示,让观众的心悬到了最高点。这也成为后来的电影情节中常见的桥段。
  在计算机的世界中,“蒙太奇”的手法,也是很常用的。特别地,在嵌入式系统中,由于来自外部硬件输入是多方面的,所以,使用,“蒙太奇”的方法,用并行的思想,来阅读理解串行方式执行的程序,会使得程序变得更容易理解。下面,我们就用“蒙太奇”的方法,来看看Stellaris开发板附带的演示程序中,网络部分的代码。

最新回复

学习中~~谢谢楼主  详情 回复 发表于 2012-10-4 16:47
 
点赞 关注

回复
举报

1672

帖子

0

TA的资源

裸片初长成(初级)

沙发
 

程序蒙太奇—— Stellaris开发板网络部分小记 (2) Ping一下

当Stellaris的以太网接口和带有DHCP服务器的交换机/路由器相连,以太网接口会获取一个IP地址,如192.168.1.102这样的地址。为了验证这个IP地址的有效性,我们可以从其他PC机ping这个地址以测试之:

C:\Documents and Settings\Richie>ping 192.168.1.102

Pinging 192.168.1.102 with 32 bytes of data:

Reply from 192.168.1.102: bytes=32 time=4ms TTL=128
Reply from 192.168.1.102: bytes=32 time=3ms TTL=128
Reply from 192.168.1.102: bytes=32 time=2ms TTL=128
Reply from 192.168.1.102: bytes=32 time=2ms TTL=128

其实,ping的过程,是分为两个阶段的:
1、PC机的以太网适配器向3S8962发出一个ARP学习请求报文,3S8962的以太网接收到以后,以一个ARP应答报文回应之;
2、PC机依据学习到的ARP表项中的MAC地址,向3S8962发出一个ICMP Echo报文,3S8962接受以后,上送lwIP协议栈处理,lpIP协议栈构造一个ARP Echo Reply报文,回应之。
 
 

回复

1672

帖子

0

TA的资源

裸片初长成(初级)

板凳
 

程序蒙太奇—— Stellaris开发板网络部分小记 (3) 发生了什么

我们可以看到,ping的两个阶段,从驱动程式的角度来看,其实是一样的:
硬件收到报文,触发一个中断,在中断处理程序中将报文上送给lwIP协议栈,lwIP协议栈回应一个报文,通过驱动再发送出来。


被MM抓去擦地了,擦完再说。
 
 
 

回复

2751

帖子

0

TA的资源

裸片初长成(初级)

4
 
原帖由 richiefang 于 2010-5-23 14:27 发表
我们可以看到,ping的两个阶段,从驱动程式的角度来看,其实是一样的:
硬件收到报文,触发一个中断,在中断处理程序中将报文上送给lwIP协议栈,lwIP协议栈回应一个报文,通过驱动再发送出来。


被MM抓去擦地了 ...


擦完没啊,等着呢。
 
 
 

回复

5979

帖子

8

TA的资源

版主

5
 

擦地擦累了,上床去了
 
个人签名生活就是油盐酱醋再加一点糖,快活就是一天到晚乐呵呵的忙
===================================
做一个简单的人,踏实而务实,不沉溺幻想,不庸人自扰
 
 

回复

1672

帖子

0

TA的资源

裸片初长成(初级)

6
 

回复 5楼 chenzhufly 的帖子

:$您也是有经验的人了...擦地和上床可都是体力活...:$
 
 
 

回复

1672

帖子

0

TA的资源

裸片初长成(初级)

7
 

程序蒙太奇—— Stellaris开发板网络部分小记 (4) 天上人间

天上人间,在这里是“天上” “人间”两个分立的词语,和最近很火的某件事情没有什么关系。
对于驱动(内核层)和应用层,在系统中,就如同天上和人间一样。数据包从网卡驱动收上来以后,就从天上进入了人间。下面,我们就来看看,天上和人间的转捩点。

安装了Stellaris开发套件以后,lwip协议栈的代码,就在这个目录:
D:\StellarisWare\third_party\lwip-1.3.0 (假设安装在D盘)

该目录下的ports/stellaris目录下,有stellaris相关的文件。其中,我们要注意函数stellarisif_interrupt,这个函数是Stellaris处理器的以太网中断服务程序(Interrupt Handler),只要以太网发生数据包接收事件,会触发中断,由这个函数来处理进入的一切数据包。
 
 
 

回复

1672

帖子

0

TA的资源

裸片初长成(初级)

8
 

4.5 打个岔 lwIP的pbuf

在这里小打一个岔,介绍一下lwIP协议栈的数据分配单元pbuf。
阅读过《TCP/IP详解》第二卷的同学,一定知道在FreeBSD中,网络数据包的处理都是基于mbuf的,每个mbuf中可以存放数据包的一个片段,他们构成的mbuf链组成了数据包。类似的,在lwIP协议栈中,定义了一个pbuf结构体,它的定义在src/include/lwip/pbuf.h中。由于lwIP多用于轻量级嵌入式系统,所以,pbuf也比mbuf简单得多。它只有以下成员:
struct pbuf {
  struct pbuf *next; /* 指向下一个pbuf */
  void *payload; /* 指向有效数据 */
  u16_t tot_len; /* pbuf链的总长度 */
  u16_t len;  /* 该pbuf的数据长度 */
  u8_t  type; /* pbuf类型 */
  u8_t flags; /* pbuf标志 */
  u16_t ref; /* 引用计数,统计有多少个指针指向这个pbuf */

#if LWIP_PTPD /* 条件编译选项,时间戳支持 */
  u32_t time_s; /* 接收到该数据包的时间,秒计数 */
  u32_t time_ns; /* 接收到该数据包的时间,毫秒计数 */
#endif
};

为什么单独打个岔写这个家伙呢?因为,随着学习的深入,我们会发现这个家伙无所不在……
 
 
 

回复

1672

帖子

0

TA的资源

裸片初长成(初级)

9
 

5 天王盖地虎 ——ARP报文处理

看过《智取威虎山》的同学一定记得这个情节,杨子荣当卧底之前对切口:
“天王盖地虎?”
“宝塔镇河妖。”
只有对上了“切口”,后面的通讯才有得谈。
以太网通信也类似。我们知道,以太网向对方发送数据包,需要知道对方的MAC地址。在只知道对方IP地址的情况下,就需要通过ARP应答机制来学习对方MAC。
发送方问:“Who has ip 192.168.1.102?” (天王盖地虎)
192.168.1.102所在的网卡回答:“I have!” (宝塔镇河妖!)
这就对上了切口,才有后面的故事:为剿匪先把土匪扮,似尖刀插进威虎山,誓把座山雕埋葬在山涧,壮志撼山岳,雄心镇深渊,待等到与战友会师百鸡宴,捣匪巢定叫他地覆天翻~~~~~~~
糟糕,不小心跑题了。我们回来继续说智取威虎山,哦,不,是lwip。

当PC机发起一次ping,并且不知道Stellaris的MAC地址的时候,PC机会送出一个ARP请求,其地址是广播MAC: ffff-ffff-ffff,交换机(switch)收到这样一个报文会将其泛洪(flooding)到除了这个包输入接口以外的每个接口上。这样,stellaris就是接收者之一。
前面说到,在这种情形下,会触发LM3S8962的以太网中断,报文在函数stellarisif_interrupt中压进软件队列,在函数stellarisif_input中取出。
stellarisif_input调用ethernet_input处理,这里是第一个分歧点。在函数ethernet_input中,进行以太网报文的分类。ARP报文的种类为0x0806,在代码中用宏ETHTYPE_ARP表示:
...
case ETHTYPE_ARP:
  etharp_arp_input(...);
  break;
...

etharp_arp_input函数的功能,就是根据RFC826,接收ARP,判断是否是自身的IP地址并回复的一个过程。
注意这一段:
   /* 判断是否是自己的IP地址 */
  if (netif->ip_addr.addr == 0) {
    for_us = 0;
  } else {
    for_us = ip_addr_cmp(&dipaddr, &(netif->ip_addr));
  }


  /* 如果是则更新自身的ARP表项 */
  if (for_us) {

    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_TRY_HARD);

  } else {

    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), 0);
  }
  
  switch (htons(hdr->opcode)) {

      case ARP_REQUEST:
    ....
    if (for_us) {
        ....
        netif->linkoutput(netif, p);
   }

大家注意到最后的这句吗? netif->linkoutput(netif, p); 这实际上是将构造的报文发送出去。netif是描述网络接口的一个结构体,linkoutput是它的一个成员,是一个函数指针,指向网络接口的发送函数。这个指针在初始化时,指向了low_level_output,最后调用low_level_transmit向硬件发送报文。这样,一个ARP应答报文就发出了。
关于ARP机制,如果想了解更多,可以查阅《TCP/IP详解》的第三章。
 
 
 

回复

3

帖子

0

TA的资源

一粒金砂(初级)

10
 
狂顶啊,楼主继续~
 
 
 

回复

69

帖子

0

TA的资源

一粒金砂(初级)

11
 
正在学习中,好帖,收藏了!
 
 
 

回复

826

帖子

0

TA的资源

一粒金砂(中级)

12
 

这个可是有难度哦!!

继续努力!!
 
 
 

回复

1672

帖子

0

TA的资源

裸片初长成(初级)

13
 

6 王八看绿豆——Ping报文的处理

有道是:
王八看绿豆——越看越对眼。
赵薇看周迅——大眼瞪小眼。
冠希看凤娇——饶了哥哥我这双眼!

言归正传。我们知道,人和人之间的沟通,往往从一个眼神开始,特别是。而网络主机之间的沟通,需要从什么开始呢?对了,是ping包。它就像互相情投意合而难以开口的青年男女互相试探一样,发出探测讯号,等待对方的回应。
在网络中,这样的探测讯号叫做ICMP(Internet Control Management Protocol)包,用于确定对方是否存在的ICMP包类型,叫做ICMP Echo。Echo在英文中是“回声”的意思,顾名思义,收到这个包的主机需要向对方回应一个包,这个包叫做ICMP Reply。
在我们的Stellaris开发板例程的lwip协议栈中,收到ICMP包以后,会经过怎样的一个处理过程呢?
我们已经知道,收到来自以太网的报文以后,会调用到函数ethernet_input。在这个函数中,一个switch-case分支,将数据包分类,只要数据包的类型为0x0800,就会调用ip_input这个函数,它是IP数据包的总入口。注意到ip_input在lwip的源码中有两个,一个是ipv4的,另一个是ipv6的。我们先来看ipv4的。
这个函数非常长,但前面的大半都是进行一些错误检查,它真正有价值的部分在后面的switch-case:
#if LWIP_RAW
  /* raw input did not eat the packet? */
  if (raw_input(p, inp) == 0)
#endif /* LWIP_RAW */
  {

    switch (IPH_PROTO(iphdr)) {
#if LWIP_UDP
    case IP_PROTO_UDP:
#if LWIP_UDPLITE
    case IP_PROTO_UDPLITE:
#endif /* LWIP_UDPLITE */
      snmp_inc_ipindelivers();
      udp_input(p, inp);
      break;
#endif /* LWIP_UDP */
#if LWIP_TCP
    case IP_PROTO_TCP:
      snmp_inc_ipindelivers();
      tcp_input(p, inp);
      break;
#endif /* LWIP_TCP */
#if LWIP_ICMP
    case IP_PROTO_ICMP:
      snmp_inc_ipindelivers();
      icmp_input(p, inp);
      break;
#endif /* LWIP_ICMP */
#if LWIP_IGMP
    case IP_PROTO_IGMP:
      igmp_input(p,inp,&(iphdr->dest));
      break;
#endif /* LWIP_IGMP */
    default:
#if LWIP_ICMP
      /* send ICMP destination protocol unreachable unless is was a broadcast */
      if (!ip_addr_isbroadcast(&(iphdr->dest), inp) &&
          !ip_addr_ismulticast(&(iphdr->dest))) {
        p->payload = iphdr;
        icmp_dest_unreach(p, ICMP_DUR_PROTO);
      }
#endif /* LWIP_ICMP */
      pbuf_free(p);

      LWIP_DEBUGF(IP_DEBUG | 2, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));

      IP_STATS_INC(ip.proterr);
      IP_STATS_INC(ip.drop);
      snmp_inc_ipinunknownprotos();
    }
  }
对于ICMP,调用函数icmp_input继续处理。
同样地,在函数icmp_input中,也有对于不同类型的数据包分类的switch-case分支,第一个就是处理ICMP_ECHO,也就是Ping包的分支,除此以外进入default分支,丢弃此包——因为lwip是用于主机而不是路由器的,不需要支持其他ICMP包类型。
对ICMP Echo报文的处理,从逻辑上来说很简单:就是构造一个同收到的包内容一样的ICMP Reply报文,回应给发送方。
这段代码比较长,就不复制出来了。它的内容大家可以自己学习。


 
 
 

回复

1672

帖子

0

TA的资源

裸片初长成(初级)

14
 

在这里做个阶段性小结

各位同学和工程师们,如果对网络编程有兴趣,将来会接触到很多协议栈,例如Linux系统或FreeBSD系统的协议栈,它们都是开源的。在其中有一个共性:不断地对数据包进行分类,调用相关的处理函数,直到Socket层。
一般地,协议栈实现的是2到4层(链路层、网络层和传输层)的内容,内部的处理函数,也分为这三层,如ether_input, ip_input, udp_process这样的函数,熟悉网络基础之后,大家一眼就能看明白这些函数的层次和作用了。
希望大家技术不断进步,有问题也欢迎和我探讨。
 
 
 

回复

49

帖子

0

TA的资源

一粒金砂(中级)

15
 
Wow...帅哥八卦技术贴...用力地顶...
 
 
 

回复

4997

帖子

19

TA的资源

裸片初长成(初级)

16
 
经典啊,学习!!!!!!
 
个人签名我的博客
 
 

回复

285

帖子

3711

TA的资源

五彩晶圆(中级)

17
 
人帅,文章更帅 呵呵
不错的分享,一点点学习下 话说楼主可真八卦 呵呵
 
 
 

回复

16

帖子

0

TA的资源

一粒金砂(中级)

18
 

回复 楼主 richiefang 的帖子

学习中,谢谢共享
 
 
 

回复

65

帖子

0

TA的资源

纯净的硅(初级)

19
 
我只会调路由器和交换机。。  进来学习的。。
 
 
 

回复

8

帖子

0

TA的资源

一粒金砂(中级)

20
 
强烈支持楼主,希望楼主能继续讲解
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表