linux 网络子系统之----TCP基础协议

目录

一、总体视图

二、具体协议

TCP

IP

ICMP

ARP

vLan


三、接受网络包的整个流程


四、网络驱动

1、普通网络驱动

2、NAPI 

五、NAT, Netfilter


一、总体视图

参考百度的说明:

TCP/IP分为4层

  • 应用层FTP SMTP HTTP ...
  • 传输层TCP UDP
  • IP 网络层IP ICMP IGMP

      ·处理来自传输层的分组发送请求,收到请求后将分组装入IP数据报,填充报头,选择路径,然后将数据报发往适当的网络接口。

      ·处理数据报。

      ·处理网络控制报文协议、即处理路径、流量控制、阻塞等。

    对应于OSI七层参考模型的网络层。本层包含IP协议、RIP协议(Routing Information Protocol,路由信息协议),负责数据的包装、寻址和路由。
    同时还包含网间控制报文协议(Internet Control Message Protocol,ICMP)用来提供网络诊断信息。

  • 网络接口层ARP RARP 以太网 令牌环FDDI ...

二、具体协议

1、 TCP

http://wlkj.ccie.gxu.edu.cn/internetGuide/internetGuide8.asp  这篇教程讲得很好,有些文章太不清不楚

  • TCP数据被封装在一个IP数据报中,格式如下: 
     

    IP首部20

    TCP首部20

    TCP数据

    TCP首部格式如下: 
     

    说明
    (1)每个TCP段都包括源端和目的端的端口号,用于寻找发送端和接收端的应用进程。这两个值加上IP首部的源端IP地址和目的端IP地址唯一确定一个TCP连接。
    (2)占4字节。TCP是面向数据流的,TCP传送的报文可看成为连续的数据流,其中每一个字节都对应于一个序号。首部中的“序号”则指的是本报文段所发送的数据中第一个字节的序号,例如,某报文段的序号字段的值是30l,而携带的数据共100字节,则本报文段的数据的第一个字节的序号是301,而最后一个字节的序号是400。这样,下一个报文段的数据序号应当从401开始,因而下一个报文段的序号字段的值应为401。

    整个要传送的字节流起始序号必须在连接时建立。


    确认号:

    例如,B正确收到了A发送过来的一个报文段,其序号字段值是501,而数据长度是200字节(序号501--700),这表明B正确收到了A发送的序号700为止的数据。因此,B期望收到A的下一个序号是701,于是B在发送给A的确认报文段中把确认号置为701。请注意,现在的确认号不是501,也不是700,而是701。


    数据偏移:

    占4bit,它指出数据开始的地方离TCP报文段的起始处有多远。这实际上就是TCP报文段首部的长度。由于首部长度不固定(因首部中还有长度不确定的选项字段),因此致据偏移字段是必要的。但应注息,“数据偏移”的单位不是字节,而是32 bit字(即4字节字)。由于4 bit能表示的最大十进制数是15,因此数据偏移的最大值是60字节,这也是TCP首部的最大长度。


    (3)当建立一个新连接时,SYN标志变1。序号字段包含由这个主机选择的该连接的初始序号ISN,该主机要发送数据的第一个字节的序号为这个ISN加1,因为SYN标志使用了一个序号。
    (4)既然每个被传输的字节都被计数,确认序号包含发送确认的一端所期望收到的下一个序号。因此,确认序号应当时上次已成功收到数据字节序号加1。只有ACK标志为1时确认序号字段才有效。
    (5)只有当ACK=1时确认序号字段才有效。当ACK=0时,确认序号无效。

    发送ACK无需任何代价,因为32位的确认序号字段和ACK标志一样,总是TCP首部的一部分。因此一旦一个连接建立起来,这个字段总是被设置,ACK标志也总是被设置为1。
    (6)TCP为应用层提供全双工的服务。因此,连接的每一端必须保持每个方向上的传输数据序号。
    (7)TCP可以表述为一个没有选择确认或否认的滑动窗口协议。因此TCP首部中的确认序号表示发送方已成功收到字节,但还不包含确认序号所指的字节。当前还无法对数据流中选定的部分进行确认。
    (8)首部长度需要设置,因为任选字段的长度是可变的。TCP首部最多60个字节。
    (9)6个标志位中的多个可同时设置为1
        ◆ URG-紧急指针有效
        ◆ ACK-确认序号有效
        ◆ PSH-接收方应尽快将这个报文段交给应用层
        ◆ RST-重建连接
        ◆ SYN-同步序号用来发起一个连接

                   在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应的报文段                中使SYN=1和ACK=1。因此,同步比特SYN置为1,就表示这是一个连接请求或连接接受报文。关于连接的建立和释放,后面还                要进行讨论。
        ◆ FIN-发送端完成发送任务

    (10)窗口

    占2字节。窗口字段用来控制对方发送的数据量,单位为字节。大家知道,计算机网络经常是用接收端的接收能力的大小来控制发送端的数据发送量。TCP也是这样。TCP连接的一端根据自己缓存的空间大小确定自己的接收窗口大小,然后通知对方来确定对方的发送窗口。假定TCP连接的两端是A和B。若A确定自己的接收窗口为WIN,则将窗口WIN的数值写在A发送给B的TCP报文段的窗口字段中,这就是告诉B的TCP,“你(B)在未收到我(A)的确认时所能够发送的数据量就是从本首部中的确认序号开始的WIN个字节。”所以A所确定的WINA是A的接收窗口,同时也就是B的发送窗口。例如,A发送的报文段首部中的窗口WIN=500,确认序号为201,则表明B可以在未收到确认的情况下,向A发送序号从201~700的数据。B在收到此报文段后,就以这个窗口数值WIN作为B的发送窗口。但应注意,B所发送的报文段中的窗口字段则是根据B的接收能力来确定A的发送窗口,不要弄混。


    TCP的流量控制由连接的每一端通过声明的窗口大小来提供。窗口大小为字节数,起始于确认序号字段指明的值,这个值是接收端期望接收的字节数。窗口大小是一个16为的字段,因而窗口大小最大为65535字节。
    (11)检验和覆盖整个TCP报文端:TCP首部和TCP数据。这是一个强制性的字段,一定是由发送端计算和存储,并由接收端进行验证。TCP检验和的计算和UDP首部检验和的计算一样,也使用伪首部。
    (12)紧急指针是一个正的偏移量,黄蓉序号字段中的值相加表示紧急数据最后一个字节的序号。TCP的紧急方式是发送端向另一端发送紧急数据的一种方式。
    (13)最常见的可选字段是最长报文大小MMS,每个连接方通常都在通信的第一个报文段中指明这个选项。它指明本端所能接收的最大长度的报文段。

    (14)报文段的发送

    TCP有三种基本机制来控制报文段的发送。第一种机制是TCP维持一个变量,它等于最大报文段长度MSS,只要发送缓存从发送进程得到的数据达到MSS字节时,就组装成—个TCP报文段,然后发送出去。第二种机制是发送端的应用进程指明要求发送报文段,即TCP支持的推送(push)操作。第三种机制是发送端的一个计时器时间到了,这时就把当前已有的缓存数据装入报文段发送出去。

    在TCP的实现中广泛使用Nagle算法[NAGL84]:算法是:若发送端应用进程将欲发送的数据逐个字节地达到发送端的TCP缓存,则发送端就将第一个字符(—个字符的长度是一个字节)发送出去,将后面到达的字符将都缓存起来。当接收端收到对第一个字符的确认后,再将缓存中的所有字符装成一个报文段发送出去,同时继续对随后到达的字符进行缓存。只有在收到对前一个报文段的确认时才继续发送下一个报文段。当字符到达较快而网络速率较慢时,用这样的方法可明显的减少所用的网络带宽,算法还规定,当到达的字符已达到窗口大小的一半或己达到报文段的最大长度时,就立即发送一个报文段。

    但有时不宜采用Nagle算法。例如在因特网上使用X Windows,并将鼠标移动的信息传到远地主机。若采用Nagle算法会使用户感到无法忍受。这时最好关闭这个算法。

    另一个问题叫做糊涂窗口综合症(silly window syndrome)[RFC 813],有时也会使TCP的性能变坏。设想这种情况:接收端的缓存已满,而交互的应用进程一次只从缓存中读取一个字符(这样就在缓存产生1个字节的空位,然后向发送端发送确认,并将窗口设置为1个字节(但发送的数据报是40字节长)。接着,发送端又传来1个字符(但发来的IP数据报是41字节长。接收端发回确认,仍然将窗口设置为一个字节。这样进行下去,网络的效率将会很低。

    要解决这个问题,可让接收端等待一段时间,使得或者缓存已能有足够的空间容纳—个最长的报文段,或者缓存已有一半的中间处于空的状态。只要出现这两种情况之一,就发出确认报文,并向发送端通知当前的窗口大小。此外,发送端也不要发送太小的报文段,而是将数掘积累成足够大的报文段,或达到接收端缓存的空间的—半大小。

        上述两种方法可配合使用。使得在发送端不发送很小的报文段的同时,接收端也不要在缓存刚刚有了一点小的空位置就急忙将一个很小的窗口大小通知给发送端。

          若发送方在规定的设置时间内没有收到确认,就要将未被确认的报文段重新发送。接收方若收到有差错的报文段,则丢弃此报文段(不发达否认信息)。若收到重复的报文段,也要将其丢弃,但要发回(或捎带发回)确认信息。这与数据链路层的情况相似。

    若收到的报文段无差错,只是未按序号,那么该如何处理?TCP对此未作明确规定,而是让TCP的实现者自行确定。或者将不按序的报文段丢弃,或者先将其暂存于接收缓存内,待所缺序号的报文段收齐后再一起上交应用层。如有可能,采用后—种策略对网络的性能会更好些。例如,发送端每个报文中含有100字节的数据,且一连发送了8个报文段,其序号分别为1,l01,201,…,701。设接收端正确收到了其中的7个,而未收到序号为201的报文段。接收端可以将序号为30l~701的5个报文段先进行暂存,而发回确认序号为201的报文段(即序号为200及这以前的都已正确收到了)。当发送端重传的序号为201的报文段正确到达接收端后,接收端就发回确认序号为801的确认,因而提高了传输效率。


    TCP协议连接过程详解


     1)、建立连接协议(三次握手)

    在连接建立过程中要解决以下三个问题。

    (A)要使每一方能够确知对方的存在。

    (B)要允许双方协商一些参数(如最大报文段长度,最大窗口大小,服务质量等)。

    (C)能够运输实体资源(如缓存大小,连接表中的项目等)进行分配。

    TCP的连接和建立都是采用客户服务端方式。主动发起连接建立的进程叫做客户(client)。而被动等待正接建立的进程叫服务器(server)。


    主机A的TCP向主机B的TCP发出连接请求报文段,其首部的同步比特SYN应置为1,同时选样—个序号x.表明在后面传送数据时的第一个数据字节的序号是x。在图8-19中,一个从A到B的箭头上标有“SYN,SEQ=x”就是这个意思。


    主机B的TCP收到连接请求报文段后,如同意,则发回确认。在确认报文段中应将SYN

    置为1,确认序号应为x+1,同时也为自己选择一个序号y。


    主机A的TCP收到此报文段后,还要向B给出确认,其确认序号为y+1。


    运行客户进程的主机A的TCP通知上层应用进程,连接已经建立(或打开)。

    当运行服务器进程的主机B的TCP收到主机A的确认后,也通知其上层应用进程,连接已经建立。


    连接建立采用的这种过程叫做三次握手(there-way handshake),或三次联络。

    为什么要发送这第三个报文段呢 这主要是为了防止己失效连接请求报文段突然又传送到了主机B,因而产生错误。

    所谓“已失效的连接请求报文段”是这样产生的。考虑这样一种情况。主机A发出连接请求,但因连接请求报文丢失而未收到确认。主机A于是再重传—次。后来收到了确认,建立了连接。数据传输完毕后,就释放了连接。主机A共发送了两个连接请求报文段,其中的第二个到达了主机 B 。


    现假定出现另一种情况,即主机 A发出的第一个连接请求报文段并没有丢失,而是在某些网络结点滞留的时间太长,以致延误到在这次的连接释放以后才传送到主机B。本来这是一个已经失效的报文段。但主机B收到此失效的连接请求报文段后,就误认为是主机A又发出—次新的连接请求,于是就向主机A发出确认报文段,同意建立连接。

    主机A由于并没有要求建立连接,因此不会理睬主机B的确认,也不会向主机B发送数据,但主机B却以为运输连接就这样建立了,并一直等待主机A发来数据。主机B的许多资源就这样白白浪费了。

     

    采用三次握手的办法可以防止上述现象的发生。例如在刚才的情况下,主机A不会向主机B的确认发出确认。主机B收不到确认,连接就建立不起来。


     2)、连接终止协议(四次分手)

      由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
      (1) TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送(报文段4)。
      (2) 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。
      (3) 服务器关闭客户端的连接,发送一个FIN给客户端(报文段6)。
      (4) 客户段发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。
      CLOSED: 这个没什么好说的了,表示初始状态。
      LISTEN: 这个也是非常容易理解的一个状态,表示服务器端的某个SOCKET处于监听状态,可以接受连接了。
      SYN_RCVD: 这个状态表示接受到了SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本上用netstat你是很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次TCP握手过程中最后一个ACK报文不予发送。因此这种状态时,当收到客户端的ACK报文后,它会进入到ESTABLISHED状态。
      SYN_SENT: 这个状态与SYN_RCVD遥想呼应,当客户端SOCKET执行CONNECT连接时,它首先发送SYN报文,因此也随即它会进入到了SYN_SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。
      ESTABLISHED:这个容易理解了,表示连接已经建立了。
      FIN_WAIT_1: 这个状态要好好解释一下,其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。
      FIN_WAIT_2:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。
      TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。
      CLOSING: 这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报文的情况,也即会出现CLOSING状态,表示双方都正在关闭SOCKET连接。
      CLOSE_WAIT: 这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。
      LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。


你可能感兴趣的:(linux 网络子系统之----TCP基础协议)