深入理解linux网络技术内幕详情,深入理解linux内核看不懂

今天是2016年的256天,法定的程序员节,如果你打开这个文章,先祝你节日快乐,看到这个关键字进来的,都是真正的程序员。

深入理解linux网络技术内幕详情,深入理解linux内核看不懂

这个文章很长,也很晦涩难懂,所以我建议你收藏或转发评论下,以备日后查找。

这个专题写了这么多篇文章,这个其实是重要的互联网无处不在,只要你一动手写代码,或早或晚都会遇到网络。

你用的是封装过的网络sdk,经常会出现莫明其妙的问题,你会把这些问题归结为网络问题,网络环境不好。但这不足以说服你的客户。

但如果是一个对tcp/ip深入理解的程序员,当他写程序时,他脑中看到的是协议包,比特流,他会小时的处理socket的每一个flag, 其它程序员常用的网络问题这个挡箭牌他从来不用,不需要用。

如果你只是来参与前文提到的编程语言之争,请移步程序员福利:掀开裙子看真相之linux文件系统

L i n u x几乎可以说是网络的一个同义词,事实上, L i n u x是一个I n t e r n e t (因特网)或Wo r l dWide We b (万维网)的产品,其开发者和用户通过网络交换一些有用的思想和代码, L i n u x本身也经常用于网络的组织管理,本章介绍L i n u x是如何支持著名的T C P / I P协议族的。T C P / I P,即传输控制协议/网际协议( Transmission Control Protocol/Internet Protocol),实

际上是一个由多种协议组成的协议族,它定义了计算机通过网络互相通信及协议族各层次之间通信的规范。

T C P / I P初是在由美国政府资助的美国高等研究计划署的网络A R PA N E T上发展起来的,该网络用于支持美国军事和计算机科学研究,正是由它提出了报文交换和网络分层概念。1 9 8 8年以后, A R PA N E T由其继任者—美国国家科学基金会的N S F N E T所取代,而N S F N E T和全世纪数以万计的局域网和区域网共同连接成了一个巨大的联合体—因特网( I n t e r n e t ),举世闻名的万维网( World Wide We b )也是来自于A R PA n e t并完全采用T C P / I P协议族。U N I X被广泛地应用于A R PA N E T,它的一个网络版是4.3 BSD (Berkeley Software Distribution),该版本支持B S D的套接字(略有扩充)和全部的T C P / I P协议,L i n u x的网络功能即是基于这个版本实现的。L i n u x之所以以该4.3 BSD版本为模型,是因为这个版本广为流行,并且它支持L i n u x与其他U N I X之间应用程序的移植。

TCP/IP网络概述

本节将概述T C P / I P网络的主要原理。在一个T C P / I P网络中,每台主机都分配有一个3 2位的I P地址,该地址可以地标识主机。I P 地址通常用“ · ”隔开的四个十进制数表示,称为点分十进制表示,如I P地址0 x 8 11 2 4 C 1 5 ( 1 6进制)通常写成1 2 9 . 1 8 . 7 6 . 2 1。

I P地址由两部分组成:网络( n e t w o r k )地址和主机( h o s t )地址。网络地址由I P地址的高位组成,主机地址由低位组成,这两部分的大小取决于网络的类型。如一个B类地址( I P地址的一个字节大小在1 2 8到1 9 1之间),其I P地址的前两个字节是网络地址,后两个字节表示主机地址,这样一个B类地址可支持6 5 5 3 6个网络,同时每个网络中可容纳6 5 5 3 6台主机。

I P地址的主机部分可以分出多个子网,利用子网技术,大的网络(即主机地址部分占较多字节)可以被分为若干小的子网( s u b n e t w o r k ),每一个子网均可独立维护。例如, I P地址1 6 . 4 2 . 0 . 9,可将其设置为子网地址1 6 . 4 2 . 0,其主机地址1 6 . 4 2 . 0 . 9,这种技术通常用来划分一个企业的网络,如将1 6 . 4 2 作为A C M E计算机公司的网络地址,那么1 6 . 4 2 . 0则为子网0,1 6 . 4 2 . 1则为子网1,这些子网或许位于相分离的建筑物中,它们通过租用的电话线甚至微波相连。通常由网络管理员为主机分配I P地址,使用了子网技术将更有助于网络管理员的分派,并且管理员在其所辖子网内可以随意分配I P地址而不会有I P地址冲突。

一般说来,点分十进制表示的I P地址不易记,而记名字则容易多了。因此,每台网络主机还有一个名字,由域名服务(Damain Name Service, DNS)负责I P地址与网络主机名的互译,并在整个因特网上发布名字—I P地址数据库。使用网络主机名使得一台机器的I P地址改变(例如,这台机器被移到了另外一个网络上)时,不必担心别人在网络上找不到这台机器,这台机器的D N S记录只是更新了I P地址,所有用网络主机名对这台机器的访问将继续有效。在L i n u x中,主机名字可静态地在/ e t c / h o s t s文件中定义;也可请求分布式域名服务器( D i s t r i b u t e dName Server, DNS)为其指定一个,这样主机必须应该知道一个或多个D N S服务器的I P地址,这些信息定义在/ e t c / r e s o l v. c o n f文件中。

当连接一台主机或访问一个We b主页时,都要通过本机的I P地址与被访问主机通信,用I P报文交换数据。I P报文分为两部分:I P报头与数据,在I P报头中,包含有源主机I P地址、目的主机I P地址、校验和和其他一些有用信息(详见图1 – 8 – 1 ),其中校验和是由源主机利用I P报文数据计算得出的,目的主机据此判断报文在传输过程中是否被破坏。为了便于控制,应用程序传输的数据可能会被分片为更小的I P报文,而I P报文的大小则由传输介质所决定:以太网报文通常要比点到点(Paint to Point Protocal, PPP)报文大一些,而目的主机在将数据交给应用程序之前,必须先重组报文。I P报头中的“标识” ( I D E N T I F I C AT I O N )域、“标志” ( F L A G )域和“片偏移”(FRAGMENT OFFSET)域用来进行数据的分片与重组。如果通过较慢的网络传输图片,那么看一下图片的显示过程,即可感受到分片与重组的过程。

同一网络中的主机相互间可直接发送报文,但不同网络中的主机要通信,则必须通过一台特殊的主机:网关( G a t e w a y )。网关(或路由器)是一台同两个或更多个网络有直接连接的节点,网关可以在网络之间交换信息,把报文从一个网络传递到另一个网络。例如,网络1 6 . 4 2 . 1 . 0与1 6 . 4 2 . 0 . 0通过一个网关相连,则所有从网络1 6 . 4 2 . 1 . 0发送到1 6 . 4 2 . 0 . 0的报文都须先

发给网关,再由网关为其选择路由,转发报文。对应于每一个目的I P地址,网关中的路由表

都提供一个入口用以查询将该报文发送到哪台主机。这些路由表动态刷新,随应用程序使用

网络的时机和网络技术的不同而改变。

Linux中的TCP/IP网络层次结构

描述了L i n u x对I P协议族的实现机制,如同网络协议自身一样, L i n u x也是通过视其为一组相连的软件层来实现的。其中B S D套接字( S o c k e t)由通用的套接字管理软件所支持,该软件是I N E T套接字层,它来管理基于I P的T C P与U D P的端到端互联问题。如前所述,T C P是一个面向连接协议,而U D P则是一个非面向连接协议,当一个U D P报文发送出去后,L i n u x并不知道也不去关心它是否成功地到达了目的主机。对于T C P传输,传输节点间先要建

立连接,然后通过该连接传输已排好序的报文,以保证传输的正确。I P层中代码用以实现

网际协议,这些代码将I P头增加到传输数据中,同时也把收到的I P报文正确地转送到T C P层或U D P层。I P层之下,是支持所有L i n u x网络应用的网络设备层,例如点到点协议(Point to Point

Protocol, PPP)和以太网层。网络设备并非总代表物理设备,其中有一些(例如回送设备)则是纯粹的软件设备,网络设备与标准的L i n u x设备不同,它们不是通过m k n o d命令创建的,必须是底层软件找到并进行了初始化之后,这些设备才被创建并可用。因此只有当启动了正确设置了以太网设备驱动程序的内核后,才会有/ d e v / e t h 0文件。A R P协议位于I P层和支持地址解析的协议层之间。

INET的套接字层

I N E T套接字( s o c k e t )层支持包括T C P / I P协议在内的I N E T地址族( Address Family),如前所述,这是一些分层协议,下层协议为上层协议提供服务。L i n u x中实现T C P / I P协议的代码与数据结构充分体现了这种协议分层。I N E T套接字层接口是通过一组I N E T地址族套接字操作现的,这些操作在网络初始化时被注册到了B S D套接字层,与其他注册的地址族一起保存在p o p s向量中。B S D套接字层通过调用注册在INET proto_ops数据结构中的I N E T套接字层例程来完成上述操作。在进行每一项操作时, B S D套接字层都要把代表B S D套接字的数据结构传给I N E T层,I N E T套接字层并非简单地抽取B S D套接字中的特定T C P / I P信息,而是使用自己的s o c k数据结构,该数据结构已被链接到BSD socket数据结构上了,在图1 – 8 – 5中给出了这种链接,这种链接通过BSD socket中的d a t a (数据)指针将s o c k数据结构链到了BSD socket数据结构上。这样以来,随后的I N E T套接字调用将会很容易的得到套接字数据结构。在创建套接字时,也建立了指向套接字数据结构的协议操作的指针,这些指针与所使用的协议有关:当使用T C P时,它们将指向与建立T C P连接有关的一组T C P协议的操作。

IP层

套接字缓冲区

协议分层为网络传输带来了一些问题,其中之一就是在利用各层发送数据时,每层都要加上自己的头部和尾部信息,而接收时又要由每层将这些信息去掉,这样就使得数据缓冲区的分配变得更为困难,因为每层都要能在缓冲区中找到特定的头部和尾部。一种解决方案是在每一层都对缓冲区进行全拷贝,但这样做效率太低。在L i n u x中,各层协议和网络设备驱动程序间只传递套接字缓冲区或s k b u ff,s k b u ff中有指针和长度域,这样各层协议即可通过标准函数或方法使用数据。图给出了s k b u ff的数据结构,每一个s k b u ff有一个相关联的数据块。s k b u ff中有4个数据指针,用于使用和管理套接字缓冲区中的数据:

head 指向内存中数据的起始区,一旦分配了s k _ b u ff及其相关数据块,即可确定该指

针。

• data 指向当前协议数据的开始,该指针取决于当前拥有s k b u ff的协议层。

• tail 指向当前协议数据尾,与d a t a一样,它也依赖于当前拥有s k b u ff的协议层。

• end 指向内存中数据的结束区,分配了s k b u ff后,该值确定。

其中有两个长度域:

a. len 当前协议报文的长度。

b. truesize 整个数据缓冲区长。

s k b u ff的控制处理代码对添加和删除协议头和尾提供了标准操作,通过这些操作可安全地使用s k b u ff中的d a t a、t a i l和l e n域:

• push 将d a t a指针指向数据开始区,并相应增加l e n域,用于向待传输数据添加数据或协议头。

• pull 将d a t a指针指向数据区的e n d,并相应减小l e n域,用于从接收到的数据中删除数据或协议头。

• put 将t a i l指针指向数据区的e n d,并相应增加l e n域,用于向发送的数据e n d处添加数据或协议信息。

• trim 将t a i l指针指向数据区起始处,并相应减小l e n域,用于从接收到的报文中删除数据或协议尾。

s k _ b u ff数据结构中还有s k _ b u ff的双向链表指针,并有通用的s k _ b u ff例程用这些指针从s k b u ff链头或链尾对s k b u ff数据结构进行添加或删除。

接收IP报文

6章曾讲述了L i n u x是如何将网络驱动程序建立到内核中并进行初始化的,这样在d e v _ b a s e链中相应就有了一系列的设备数据结构,每个设备数据结构描述了其设备并提供了一组回调例程。当网络各协议层需要网络驱动程序为其工作时,就要调用这些例程,它们通常和使用网络设备地址的数据传输有关。当网络设备从网上接收到报文后,必须先将接收到的数据转换到s k b u ff数据结构中,然后把s k b u ff添加到b a c k l o g队列中。当b a c k l o g队列太长时,新接收到报文的s k b u ff将被抛弃,一旦队列中有待处理的s k b u ff,网络bottom half即被置为可用状态。

网络bottom half控制处理进程被调度器激活后,先处理待发送报文,然后处理s k b u ff的b a c k l o g队列,以决定向哪一层递交接收到的报文。L i n u x初始化网络各层时,每种协议都要注册,它们分别把各自的p a c k e t t y p e数据结构加入到p t y p e a l l或p t y p e b a s e表中。p a c k e t – t y p e数据结构中包括有协议类型、一个网络设备指针、一个协议接收数据处理例程指针和一个指向

下一个p a c k e t t y p e数据结构的指针(用于维护表或哈希链)。p t y p e a l l链用于检测从网络设备接收到的非常用协议报文。p t y p e b a s e哈希表以协议标志为索引,用以判别将接收到的网络报文递交给哪个协议。网络bottom half进程对协议类型进行匹配,以免在上述两类表中找到多个入口,但当检测所有网络传输时,的确可能匹配到不止一个入口,这种情况下,将复制s k b u ff,所有s k b u ff都将递交给匹配到的协议处理例程。

地址解析协议

地址解析协议(Address Resolution Protocol, ARP)的任务就是实现I P地址和物理硬件地址(如以太网地址)间的互译,在把数据交由设备驱动程序进行发送之前,I P需要先得到解析结果。对于判别设备是否需要硬件头以及若需要则是否应重建硬件头, I P有多种检测方法, L i n u x通过缓存硬件头来避免对它们的多次重建。若硬件头确需重建,则调用设备特定的硬件头重建例程,所有的以太网设备使用同一个重建例程,该例程利用A R P服务将目的I P地址转化为相应的物理地址。

A R P协议本身很简单,仅包括两种消息类型: A R P请求与A R P应答。A R P请求中包含有欲解析的I P地址,应答报文中则包含了对相应I P地址的解析结果—硬件地址。

IP路由

进行I P寻径时,首先检测路由缓存,若无匹配的路由信息,再搜索转发信息数据库(Forwarding Information Database),如果仍不成功,则本次I P报文发送失败,并通知应用程序;如果找到了路由信息,就生成一个包含该信息的新入口,并将其加入到路由缓存中。路由缓存是一张表( i p r t h a s h t a b l e ),表中包含了r t a b l e数据结构链指针,对路由表的检索是通过哈希函数完成的,这个哈希函数以I P地址中不重要的两个字节为参数,这两个字节应以如下规则选定:对于不同的目的地址应尽可能不相同,这样做可以提供更好的哈希值。每个r t a b l e入口包含了路由信息:目的I P地址、到达目的I P地址所要用到的网络设备、消息长度等等。它还有一个引用计数、一个使用计数和一个上次被使用的时间戳。每次用到一个路由,就将其引用记数增1,以标明使用该路由的网络连接数量;应用程序不再使用该路由时,就将引用记数减1。使用计数是在每次对其路由进行了查找时增1,以此在哈希入口链中对路由入口排序。上次被使用的时间戳用于对路由表周期地检测,以便找出旧的信息入口,若某个路由近未被使用过,则将其删除。路由缓存中的入口以使用次数排序是为了使利用率的路由放在哈希队列头,这样可提高路由查找效率。

$$$$$$$$$$$$

更多精彩,请访问我们的网站:我爱狄八哥(52debug@net )我爱狄八哥,我爱debug,华语地区的技术类垂直社区52debug。net

:coding-art (编码之妙)

:debug51(我爱debug) 点下订阅点个赞,

小编今天的工资,全靠你了。若是能转发下,明天的就更有干劲了。

看到这里,发一则告示:tango.unity虚拟现实技术 q q 群号:318423655

$$$$$$$$

解密:你的老板是如何打败你的

乔帮主地下显灵:不要惹程序员

版权声明:《深入理解linux网络技术内幕详情,深入理解linux内核看不懂》文章主要来源于网络,不代表本网站立场,不承担相关法律责任,如涉及版权问题,请发送邮件至[dcseo8@163 。com]举报,我们会在第一时间进行处理。本文文章链接:https://www.dcseo.cn/39176.html
(0)

相关推荐