传输层---深入理解UDP/TCP协议

传输层---深入理解UDP/TCP协议

传输层:负责数据能够从发送端传输到接收端

吐舌头我们先来看一下端口号:

   1> 端口号(port)标识了一个主机上进行通信的不同应用程序.

   

 在TCP/IP当中,用"源IP","源的端口号","目的IP","目的端口号","协议号"这五元组来标识一个通信.

2> 端口号范围划分

    0-1023:知名端口号,HTTP,FTP,SSH等这些广为使用的应用层协议,它们的端口号都是固定的.

    1024-65535:操作系统动态分配的端口号,客户端程序的端口号,就是由操作系统从这个范围分配的

3>认识知名端口号(cat /etc/services指令可以查看端口号)

    ssh服务器端口号:22

    ftp服务器端口号:21

    telent服务器端口号:23

    http服务器端口号:80

    https服务器端口号:443

    注意我们自己写程序时,要尽量避开这些端口号

吐舌头关于端口号我们需要注意的两个问题

    1.一个进程是否可以bind多个端口号?(可以)

    2.一个端口号是否可以被多个端口号绑定?(不可以,若是一个进程已经绑定,再去fork(),是可以实现的)

二.查看网络和服务器pid的重要工具

 通过 netstat  -n | grep 文件名  来查看网络状态

 通过 pidof  进程名 查看进程id,查看服务器进程比较方便

三.UDP协议      

   1>UDP协议端格式


2>UDP特点

  ①无连接:知道对端的IP和端口号就直接进行传输,不需要进行建立连接

  ②不可靠:没有确认机制,没有重传机制,如果因为网络故障该段无法发到对方,UDP协议层也不会给应用层返回任何错误信息.

  ③面向数据报:不够灵活的控制读写数据的次数和数量.

  ④全双工:socket既能读也能写

面向数据报----应用层交给UDP多长的报文,UDP原样发送,既不会拆分,也不会合并.

3>UDP缓冲区

   UDP没有真正意义上的发送缓冲区,调用sendto会直接交给内核,由内核将数据传给网络层协议进行后续的传输工作.

   UDP具有接收缓冲区,但是这个接收缓冲区不能保证收到的UDP报的顺序和发送的一致,如果缓冲区满了,再到达就会丢弃.

4>UDP注意事项

    UDP协议首部中有一个16位的最大长度,也就是说一个UDP能够传输的数据最大长度是64K(包含UDP的首部)

    那么64K在互联网环境下,是一个非常小的数字.

    如果我们需要传输的数据超过64K,就需要在应用层手动的分包,多次发送,并在接收端手动拼装.

5>基于UDP的应用层协议

    NFS:网络文件系统

    TFTP:简单文件传输协议

    DHCP:动态主机配置协议

    BOOTP:启动协议(用于无盘设备启动)

    DNS:域名解析协议

四.TCP协议 

    (传输控制协议)  ---对数据的传输进行一个详细的控制

    1>TCP协议段格式


  2>面向字节流:

     创建一个TCP的socket,同时就会再内核中创建一个发送缓冲区和接收缓冲区.由于缓冲的存在,就不需要读和写一一匹配.

  3>粘包问题

     由于TCP是面向字节流,所以就会出现粘包问题,那该如何处理呢?就需要明确两个包之间的边界

     对于UDP不存在粘包问题,因为UDP是面向数据包的.

 4>基于TCP的应用层协议 

    HTTP   HTTPS    SSH   Telnet    FTP   SMTP

吐舌头TCP机制

      1>连接管理机制

         在正常情况下,TCP要经过三次握手建立连接,四次挥手断开连接.


吐舌头吐舌头这里注意如果触发了,捎带应答机制,就有可能变成三次

客户端状态转化:

  a>:[CLOSED_SYN_SENT]客户端调用connect ,发送同步报文段

  b>:[SYN_SENT-->ESTABLISHED]connect调用成功,则进入ESTABLISHEND状态,开始写数据;

  c>:[ESTABLISHED-->FIN_WAIT_1]客户端主动调用close,向服务器发送结束报文段,同时进入FIN_WAIT_1;

  d>:[FIN_WAIT_1-->FIN_WAIT_2]客户端收到服务器对结束报文段的回应确认,则进入FIN_WAIT_2,开始等待服务器关闭

  e>:[FIN_WAIT_2-->TIME_WAIT]客户端收到服务器发来的结束报文段,进入TIME_WAIT,并发送LAST_ACk给服务器;

  f>:[TIME_WAIT-->CLOSED]客户端要等待一个2MSL(报文最大生存时间),才会进入CLOSED状态.

服务器状态转化:

  a>:  [CLOSED-->LISTEND]服务器调用listen后进入LISTEN状态;

  b>:  [LISTEND-->SYN_RCVD]一旦监听到连接请求(同步报文段),就将该连接放入内核等待队列中,并向客户端 发 送SYN确认报文;

  c>:   [SYN_RCVD-->ESTABLISHED]服务端一旦收到客户端的确认报文,就进入ESTABLISHED状态,可以进行读写数据了;

  d>:  [ESTABLISHED-->CLOSE_WAIT]当客户端主动关闭链接(调用close),服务器就会收到结束报文段,服务器返回确认报文段,并进入CLOSE_WAIT;

  e>:   [CLOSE_WAIT-->LAST_ACK]进入CLOSE_WAIT后说明服务器要准备关闭连接了,但是服务器要处理完之前的数据,当服务器真正调用close关闭;连接时.会向客户端发送FIN,此时服务器进入LAST_ACK状态,等待最后一个ACk到来(客户端确认收到了FIN);

  f>:   [LSAT_ACK-->CLOAED]服务器收到了客户端的ACK,彻底关闭连接;

理解TIME_WAIT状态

       TCP协议规定,主动关闭连接的一方先处于TIME_WAIT状态,等待两个MSL(数据报从发送端到接收端所用的最大的时间)的时间后才能回到CLOSED状态

       服务器在TIME_WAIT期间不能监听同样的server端口

       MSL在RFC1122中规定为2分钟,但是各种操作系统的实现不同,在centen7上默认的是60s

      cat /proc/sys/net/ipv4/tcp_fin_timeout   查看msl的值

   2>确认应答(ACK)机制


  3>超时重传机制(内核实现)

         上图中主机A发送数据给B后,可能因为网络堵塞的原因,数据无法到达主机B

          如果主机A在一个特定的时间间隔内没有收到B发来的确认应答,就会进行重发(主机A未收到B发来的确认应答有可能是因为ACK丢失).

         所以主机B就会收到许多重复的数据,要对这些数据进行处理,就需要能够识别出哪些是重复的包,并且把重复的包丢弃掉.

         这时候我们可以利用前面提到的序列号,就可以很容易的做到去重的效果

         那么超时的时间该如何确定呢? 

                超时的时间---不同的系统实现的方式不一样,最理想的情况下,找到一个最小的时间,保证"确认应答一定能在这个时间内返回".

                TCP为了保证在任何环境下都能够比较高性能的通信,因此会动态计算这个最大超时时间.

                Linux中,超时以500ms为一个单位进行控制,每次判定超时重发的超时时间都是500的整数倍.如果重发一次得不到回应,等待2*500ms后再重传一次.如果仍然得不到应答,就等待4*500ms进行重传,以此类推,以指数增长,累计到一定次数,TCP认为网络或者对端主机出现异常,强制关闭连接.

   4>滑动窗口

        在确认应答机制下,对每一个发送的数据段,都要给一个ACK确认应答,收到ACK后再发送下一个数据段,这样的话,性能差,尤其是在数据往返的时间较长的时候.


       在此之下,我们引入滑动窗口.

       窗口大小:是指(一次批量发送数据的最大值)无需等待确认应答而可以继续发送数据的最大值.(上述图的窗口大小就是4000个字节,共4个字段.一个字段1000个字节)

       发送前4个字段的时候, 不需要等待任何ACK,直接发送,收到第一个ACK,滑动窗口向后移动,继续发送第五个段的数据,依次类推

        操作系统内部为了维护这个滑动窗口,需要开辟"发送缓冲区",来记录当前还有哪些数据没有应答,只有确认应答过的数据,才能从缓冲区中删掉.

        窗口越大,则网络的吞吐率就越高.

   

    在这里,如果批量发送,出现了丢包,如何进行重传呢?

            a>如果是数据报已经抵达,ACK丢了,这种情况下,不用担心,因为后续的ACK可以进行确认.

             b>数据报丢了

                

       当某个报文段丢失之后,如上图所示,发送端会一直收到 1001这样的ACK,如果连续收到3次同样的"1001"应答,就会将对应的数据1001-2000重新进行传送; 这个时候接收端收到了,就会返回的ACK就是"7001"了,因为2001-7000在此之前就已经收到存到内核的接收缓冲区了.(这种机制被称为"高速重发控制"也叫"快重传")

     5>流量控制

        对于接收端,处理速度也是有限的,如果发送端发送的太快的话,导致接收端的缓冲区满了,这个时候如果发送端继续发送的话,就会造成丢包,继而引起丢包重传的一系列连锁反应.

      因此TCP支持根据接收端的处理能力,来决定发送端的发送速度,这个机制叫做流量控制

       a>接收端将自己可以接受的缓冲区大小放入到TCP首部中"窗口大小"的字段(16位),通过ACK端通知给发送端,

       b>窗口大小字段越大,说明网络的吞吐量越高

       c>接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端

       d>发送端接收到这个窗口后,就会减慢自己的发送速度

       e>接收端缓冲区满了, 就会将窗口大小设置成0,这时发送方不再发送数据,但是定期发送一个窗口探测数据段,使接收端把窗口大小告诉发送方.

TCP首部中"窗口大小"的字段(16位),最大表示65535字节,实际上,在TCP首部40个字节的选项中还包含了一个扩大因子M,实际窗口大小是窗口大小字段的值左移M位.

    6>拥塞控制

     TCP引入慢启动机制,先发少量的数据,探探路,看看当前的网络状态,再决定按照多大的速度传输数据

     发送开始的时候,定义拥塞窗口为1,每次收到ACK应答,拥塞窗口加1,每次发送数据包的时候,将拥塞窗口和接收端主机反馈的窗口大小做比较,取较小的值作为实际发送的窗口.

    上面所述的拥塞窗口是指数级别的,慢启动只是初始比较慢,但是增长的非常快, 为了不很快的增长,引入慢启动的阀门,当拥塞窗口超过这个阀门时,不再按照指数的方式增长,而是按照线性方式增长.


7>延迟应答

     如果接收数据的主机立刻返回ACK应答,这时候返回的窗口大小可能会比较小,但实际上处理端的速度可能会很快,而延迟应答就会使缓冲区的数据处理一波后再返回,这样的话返回的窗口就会比较大

   这样的话窗口越大,网络的吞吐量就会越大,传输的小路也就会越高,就可以保证在网络不拥堵的情况下,尽量提高传输的效率.

8>捎带应答

在延迟应答的基础上,我们可以捎带应答,有些情况下,ACK就可以搭顺风车,把服务器回应一起返回给客户端.

吐舌头TCP异常情况

  进程终止:进程终止会释放文件描述符,仍然可以发送FIN,和正常关闭没有什么问题

  机器重启:和进程终止一样.


猜你喜欢

转载自blog.csdn.net/sx2448826571/article/details/80376703
今日推荐