计算机网络---传输层(tcp、udp)

目录

一、再谈端口号

1、端口号范围划分

2、相关指令

二、UDP协议

1、udp协议格式

2、udp的特点

4、udp使用注意事项及基于udp的应用层协议

三、TCP协议

1、tcp协议格式

2、tcp报头解释

3、TCP确认应答机制

4、TCP超时重传机制

5、tcp三次握手四次挥手

6、滑动窗口

7、流量控制

8、拥塞控制


一、再谈端口号

端口号用来唯一标识一台主机上通信的进程,在tcp协议中用“源ip”、“源端口”、“目的IP”、“目的端口”、“协议号”这样一个五元组来标识一个通信。

计算机网络---传输层(tcp、udp)_第1张图片

1、端口号范围划分

  • 0 - 1023: 知名端口号 , HTTP, FTP, SSH 等这些广为使用的应用层协议 , 他们的端口号都是固定的 .
  • 1024 - 65535: 操作系统动态分配的端口号. 客户端程序的端口号, 就是由操作系统从这个范围分配的.

一些知名端口号:

  • ssh服务器使用22号端口号;
  • ftp服务器使用21号端口号
  • telnet使用23号端口号
  • http使用80端口号
  • https使用443端口号

2、相关指令

1)查看知名端口号

cat  /etc/services

2)netstat查看网络状况

netstat选项

  • n:拒绝显示别名,能显示数字的全部转化成数字。
  • l:列出所有在listen服务状态
  • p:显示建立相关链接的程序名
  • t:只显示tcp相关选项
  • u:只显示udp相关选项
  • a:显示所有选项,默认不显示listen相关

3)查看服务器的进程id--pidof

pidof  进程名

思考1:一个进程可以bind多个端口号?

可以,一个进程可以绑定多个端口号,通过这些端口号都可以找到这个进程。

思考2:一个端口号可以被多个进程bind? 

不可以,端口号的作用是唯一标识一台主机上的具体某一个进程,如果多个进程都绑定一个端口号就失去了端口号的意义。

二、UDP协议

用户数据报协议(udp)是工作在传输层的一个重要协议,UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。

1、udp协议格式

计算机网络---传输层(tcp、udp)_第2张图片

思考1:上层协议是如何将udp协议的报头和有效载荷(数据)分离?

udp的报头是一个8字节的定长报头,当拿到一个udp数据报是读取到的前8个字节就是报头,报头中包含一个16位的udp长度字段,通过该字段计算出udp有效载荷大小。这样就将udp报头和有效载荷成功分离。

思考2:udp协议最多可以传送多少数据?

注意:16位udp长度可以认为是一个unsigned类型,且16位udp长度包括报头的8字节。

16位udp长度最多可以表示65535个字节,而报头占8字节,因此udp有效载荷最大长度为65535-8=65527字节。

思考3:udp协议如何保证用户数据报的完整性? 

udp称为用户数据报协议,因此一定要保证用户数据报的完整性,具体做法就是8字节报头+16位丷长度来计算有效载荷长度,从而确保上层协议拿到的是一个完整的数据报。

思考4:16位检验和有什么作用?

udp是一个无连接不可靠的传输层协议,它的检验和只是用来检验数据本身是否出错。由于udp的不可靠性,一旦检测到检验和出错,udp协议直接将该数据包丢弃。

总结:udp协议通过协议包头中的16位的源端口和16位的目的端口直到自己“从哪来,到哪去”,通过16位udp长度直到自己携带了多大的数据报,并且可以通过这16位udp长度将报头和有效载荷进行分离。还有一个16位的检验和,用来验证数据报是否出错,如果出错直接丢弃。

2、udp的特点

udp协议有以下三个主要特点:

  • 无连接:直到对端的IP地址和端口号就可以直接进行传输,不需要建立连接。
  • 不可靠:没有确认机制,没有重传机制。如果因为网络原因导致数据丢失等,udp协议层也不给应用层返回任何信息。
  • 面向数据报:传输的数据的单位是数据报。
  • 由于udp是面向数据报的,就导致udp不能灵活的控制数据的传输和接收次数,udp交给应用层的报文udp就原样发送既不会拆分也不会合并。也就是说,应用层交给udp100个字节的数据,udp一次就传输100个字节的数据,接收端也必须一次接收完100个字节的数据。

其次udp还有以下特点:

  • udp的socket是全双工的(同一时间既能读取数据也能写入数据)
  • udp没有真正意义的发送缓冲区但是具有接收缓冲区。

udp的缓冲区:

udp是全双工的,同一时间可以同时进行读和写数据,但是如果数据量较大时就有可能导致数据处理不过来,因此需要缓冲区将数据存起来。

  • udp没有真正意义的发送缓冲区,调用sendto会直接交给内核, 由内核将数据传给网络层协议进行后续的传输动作
  • udp具有接收缓冲区,但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致; 并且如果缓冲区满了, 再到达的UDP数据就会被丢弃。

4、udp使用注意事项及基于udp的应用层协议

udp可以传输的数据大小为2^16字节(64k),在当今的互联网环境下是一个非常小的数字,因此如果需要传送大于64k的数据就需要在应用层手动分包多次发送,并在接收端手动拼接。

基于udp的应用层协议:

  • NFS: 网络文件系统
  • TFTP: 简单文件传输协议
  • DHCP: 动态主机配置协议
  • BOOTP: 启动协议(用于无盘设备启动)
  • DNS: 域名解析协议

三、TCP协议

TCP全称为传输控制协议,主要功能是对数据的传输进行详细的控制。

1、tcp协议格式

计算机网络---传输层(tcp、udp)_第3张图片

tcp协议的报头是不定长的,报头的首部有一个4位字段表示报头的长度,具体表示的是该tcp 报头有多少个32bit(4字节),也就是说规定了tcp报头最大长度为(2^4-1)*4 = 60字节。由于tcp传输的是字节流,因此tcp的有效载荷可以是任意长度的。

同样的,头部8个字节源端口和8个字节目的端口表示数据“从哪来到哪去”。由于tcp是面向连接的可靠传输,因此在tcp的头部还有很多字段用来确保数据的可靠传输(后面详细讲)。

2、tcp报头解释

  • 源端口:表示发送数据的进程
  • 目的端口:接收数据的进程
  • 32位序号:发送的数据的序号
  • 32位确认序号:接收到的数据的确认号(一般为序号+1)
  • 4位首部长度:表示tcp首部长度(20~60字节)
  • 6位标志位

URG:紧急指针是否有效

ACK:确认号是否有效

PSH:当接收端缓冲区满时,且一直没有拿走数据,发送端会发送一个PSH标志位为1的数据,提示接收端应用快速将缓冲区的数据取走。

PST:重新建立连接,携带PST标志位的报文称为复位报文段。

SYN:请求建立连接,携带SYN标志位的报文称为同步报文段。

FIN:关闭连接,携带FIN标志位的报文称为结束报文段。

  • 16位窗口大小:接收端的缓冲区大小是有限的,给接收端发送数据将接收缓冲区填满后如果在继续发送,则会将原来的数据覆盖,因此tcp协议会将自己的接收缓冲区的剩余大小保存在16位窗口大小中和数据一起发送过去。需要注意的是,在tcp进行三次握手时就会进行第一次窗口大小的“协商”。
  • 16位校验和:发送端填充, CRC校验. 接收端校验不通过, 则认为数据有问题. 此处的检验和不光包含TCP首部, 包含TCP数据部分.
  • 16位紧急指针:标识哪部分数据是紧急数据。

3、TCP确认应答机制

tcp进行的是可靠传输,传输的是字节流。因此,对于tcp协议需要做到以下两点:①确保接收端成功接收到数据②确保接收端接收到数据的有序性。

网络中存在许多复杂的情况,因此并不能保证接收端接收到的数据的顺序就是发送端发送的顺序,因此tcp协议需要确保接收端接收到数据后能够按照正确的顺序对数据进行处理。

确认应答机制:发送方每发送一个数据,接收方就要向发送方发送一个确认信号,表明自己已经收到该数据,从而确保接收端成功接收到数据。

计算机网络---传输层(tcp、udp)_第4张图片

思考:tcp 是如何实现确认应答机制并且确保接收到的数据的顺序的?

在tcp报头中,有两个4字节的字段,分别表示的是32位序号和32位确认序号。tcp协议对将每个字节的数据都进行了编号,这个编号就是序号。在发送数据时会将数据的编号放在报头的32位序号中一起发送过去,接收端接收到数据后会发送一个包含32位确认序号的数据,32位确认序号表示的意思是已经接受度奥x号数据期望收到x+1号数据。例如,上图中发送端发送1~1000号数据,接收端接收到会给发送端发送确认号为1001的确认数据,表示自己已将将1000之前的所有数据都接收到了,希望下次接收到的是1001号数据。这样,tcp协议就完美的实现了确认应答机制。同时tcp协议还可以通过32位序号将接收到的序号按照发送顺序进行处理,保证数据的顺序不会出错。

计算机网络---传输层(tcp、udp)_第5张图片

注意:确认应答机制永远也不能对所有的数据进行确认,总是会有最后一条数据无法确认。因此确认应答机制并不对确认数据进行确认。

4、TCP超时重传机制

tcp协议在保证数据可靠传输是,还需要确保丢失的数据能够重新发送。因为,在主机A发送给主机B的数据可能由于网络原因导致数据发送失败,因此主机A也就收不到主机B的确认。在tcp协议中,如果主机A给主机B发送一个数据,在规定时间内主机A没有收到数据B的确认,主机A 就认为该数据丢失了(实际上不一定是丢失了,有可能是网络拥堵数据正在发送),会将该数据重新发送给主机B,这就是超时重传机制。

计算机网络---传输层(tcp、udp)_第6张图片

无论是数据发送失败(接收端确实没有接收到数据),还是数据还没发送过去或者只是确认数据发生丢包(接收端接收到了数据),一旦超时发送端都会将该数据重新进行发送,那么一定会导致接收端存在很多重复的数据,那么该如何设置超时时间呢?

最理想的情况就是找一个最小时间,确保数据在这个时间内一定能够到达。但是这个时间的长短随着网络环境的变化,是不同的。如果时间设置过长会影响传输速率,如果时间设置过短有可能会频繁发送重复的包。

TCP为了保证无论在任何情况下都能比较高性能的通信,会动态计算这个时间。在linux中超时时间以500ms为一个单位,每次判断超时重发的时间都是500ms的整数倍。如果重发一次仍然得不到应答,会等待500*2ms后进行重传,如果还是不能得到应答则在等待4*500ms重发,以此类推。当累计到一定次数,tcp会认为对端或者网络出现异常,直接强制断开连接。

5、tcp三次握手四次挥手

在正常情况下 , TCP 要经过三次握手建立连接 , 四次挥手断开连接。具体过程如下图:

计算机网络---传输层(tcp、udp)_第7张图片

三次握手过程

1)如何理解连接

对于服务器来说,服务器是1对多的,一个服务器可能要被很多个客户端连接。因此,服务器端需要将众多的连接进行管理,这就导致服务器得为这些连接建立相应的数据结构,同时这些操作也是需要时间的。所以,建立连接是需要时间+空间代价的。

2)三次握手过程

  • 一般情况下,第一次连接请求是由客户端主动发送的。
  • 客户端向服务器发送一个SYN请求,并将自己置为SYN_SENT状态,阻塞等待服务器的应答。
  • 服务器收到客户端的请求后,会向服务器端发送一个SYN+ACK数据包。表示服务器端收到客户端的请求,并且向客户端也发起连接请求。此时,服务器端变为SYN_RCVD,等待客户端的确认。
  • 客户端收到服务器端的SYN+ACK数据包后会再次向服务器端发送一个ACK确认数据包,发送成功后客户端置为ESTABLISHED状态,并且认为已经连接成功。
  • 当服务器端收到客户端的ACK确认后,此时双方建立连接成功,服务器置为ESTABLISHED状态。

3)为什么是三次握手?

  1. 如果是1次握手,客户端给服务器端发送一个连接请求直接就连接成功了,这与udp五连接有什么区别?建立连接是为了更好的管理,一次握手建立连接很容易遭到黑客的SYN洪水攻击,导致服务器宕机。
  2. 如果是2次握手,客户端向服务器端发送一个请求,服务器端向客户端发送一个确认,到此请求建立成功。那么存在一个问题,服务器端发送的ACK确认如果丢失了,此时服务器认为已经建立连接成功了,而客户端没有收到服务器的ACK确认认为没有建立连接成功,就会进行超时重传,这样就可能导致服务器端资源浪费,同时2次握手也容易遭到SYN洪水攻击。
  3. tcp传输数据时,最新的数据永远是无法保证可靠性的(最新的数据不会进行确认),当进行三次握手时,只要前两次失败客户端和服务器端就会认为连接没有建立成功。但是,如果第3三次握手失败,此时客户端认为建立成功了而服务器端认为没有建立成功,不会为其创建相应的数据结构,并且服务器端没有收到客户端的ACK确认就会进行超时重传,当重传次数达到一定程度后就直接强制断开连接,因此也不会对客户端造成很大的影响。但是,如果是四次连接就会导致服务器端认为连接建立成功,而客户端认为没有建立成功,此时浪费的是服务器资源,服务器是1对多的,如果大量的客户端对服务器连接都出现这种问题,就会给服务器带来巨大的资源浪费,甚至导致服务器崩溃。当然,五次握手和三次握手结果是相同的,但是三次握手是最小保证可靠连接的次数,相比于5/7...节省时间。
  4. 总结:为什么三次握手可以,第一个原因就是让吴福气不要出现建立误判情况,浪费服务器资源;其次还有一个重要原因就是,以最小成本验证全双工(tcp是全双工的,三次握手就可以保证全双工通信信道的场通)。

四次挥手过程

1)为什么是四次挥手

断开连接是需要上方同时建立起断开连接状态的,因此需要互相请求和确认,一共就是四次挥手。

2)四次挥手的过程

  • 客户端向服务器端发送FIN断开连接请求,发送成功后客户端置为FIN_WAIT1状态。
  • 服务器端收到客户端的FIN请求后,需要向客户端发送一个ACK确认。发送成功后,服务器端置为CLOS_WAIT状态。
  • 客户端收到服务器端的ACK确认后进入FIN_WAIT2状态。
  • 服务器端给客户端发送FIN断开连接请求,并进入ALST_ACK状态。
  • 客户端向服务器端发送ACK确认,进入TIME_WAIT状态,此时客户端并没有立刻断开连接。
  • 服务器端收到客户端的ACK确认后关闭连接,此时服务器端进入CLOSED状态,断开连接成功。

理解TIME_WAIT和CLOSE_WAIT状态

1)TIME_WAIT状态

为什么客户端给服务器端发完ACK确认后,没有立刻进入CLOSED状态?

对于客户端的最后一次ACK确认,服务器端不会在进行确认,如果客户端立刻进入CLOSED状态,有可能导致服务器端并没有接收到ACK确认,对FIN进行超时重传,但是此时客户端已经断开连接,服务器端是一直收不到客户端确认的,只能等到重传次数到达一定程度强制断开连接。因此,在客户端发送完确认后会等待一段时间,如果在改时间内没有收到服务器端重传的FIN数据就会断开连接,否则对重传的FIN重新进行确认,确保服务器端收到并断开连接。

其次,客户端发送完ACK确认进入TIME_WAIT状态,还有一个重要作用就是防止网络中没有传完,保证历史数据在网络中消散。

2)如何验证TIME_WAIT状态?

首先启动 server, 然后启动 client, 然后用 Ctrl-C 使 server 终止 , 这时马上再运行 server, 结果是绑定失败。这是因为 , 虽然 server 的应用程序终止了 , TCP 协议层的连接并没有完全断开 , 因此不能再次监 听同样的 server 端口。
解决TIME_WAIT等待引起的绑定失败:
set|socktop接口,即使㝉端口处于监听状态也可以进行绑定。

3)CLOSED_WAIT状态

首先屏蔽服务器daunt程序中关闭文件描述符的代码,启动服务器,让客户端进行链接,客户端连接成功后关掉客户端,此时客户端就想服务器端发送了断开连接的请求,但是由于服务器端屏蔽了close,无法断开连接。此时,查看服务器状态就为CLOSE_WAIT状态。

总结:对于服务器上出现大量的 CLOSE_WAIT 状态 , 原因就是服务器没有正确的关闭 socket, 导致四次挥手没有正确 完成. 这是一个 BUG. 只需要加上对应的 close 即可解决问题。

6、滑动窗口

前面讨论的确认应答策略是基于“一次发送,一次确认”,经过“一次发送,一次确认”完成后才能进行下一次发送,这样数据的传输效率会很低。

计算机网络---传输层(tcp、udp)_第8张图片

但是,确认应答机制很好的保证了数传输的安全性,为了解决其传输效率问题,又引入滑动窗口。华东窗口是指,可以一次性发送一批数据,这一批数据发送的过程不需要等待其中某一个数据的确认,窗口大小就是指这批数据的最大值。

如下图:

  • 发送前四个段时,不需要等待任何ACK,直接将四个段发送完。
  • 收到第一个ACK后,滑动窗口向后移动继续发送接下来的四个段。以此类推

计算机网络---传输层(tcp、udp)_第9张图片

操作系统内核为了维护这个滑动窗口 , 需要开辟 发送缓冲区 来记录当前还有哪些数据没有应答 ; 只有确 认应答过的数据, 才能从缓冲区删掉。 窗口越大, 则网络的吞吐率就越高 ;

计算机网络---传输层(tcp、udp)_第10张图片

  • 在上面这个图中,整个区域表示的是发送缓冲区。白色区域是滑动窗口
  • 滑动窗口中的数据是已经发送等待确认的数据。
  • 滑动窗口之前的数据是已经发送并且已经收到确认的数据。
  • 滑动窗口之后部分的数据是还没有发送的数据
  • 当接收到一个ACK时,滑动窗口的左边会右移。
  • 当接收缓冲区(16位窗口大小)变大时,滑动窗口右边右移。因此,当滑动窗口越大时,表示对方的接收能变强。
  • 滑动窗口大小除了受对方接收缓冲区剩余大小的影响,还跟拥塞控制有关(后边详细讲解)。因此,滑动窗口越大还表明网络状况好,网吞吐率高。

新的技术的引入,必然会带来一些新的问题和挑战,滑动窗口虽然解决了数据传输效率低问题,那么如果数据丢包又该如何重传呢?

  • 接收端收到了数据,但是接收端发送的ACK丢了。

计算机网络---传输层(tcp、udp)_第11张图片

其实,滑动窗口机制已经很好的解决了这个问题,滑动窗口中是可以容忍部分ACK丢包的,只要后续ACK进行确认即可(ACK确认序号表示的是该序号之前的所有数据都已经收到,接下来向收到的数据的序号)。例如,上图中1001的ACK丢了并不影响,只要后边任意一个到达都表示1~1000的收据已经收到。

  • 数据报丢了,接收端,没有收到。

计算机网络---传输层(tcp、udp)_第12张图片

当数据包真正丢失了,是需要进行重传的,这也就要求滑动窗口中发送的ACK要确保他之前的数据都已经接收到。例如,接收端接收到的数据的顺序是1~1000、5001~6000、4001~5000,当接收到5001~6000的数据后不能立即发送6001的ACK,必须等到6001之前的数据全部到达才能发送。

其次,滑动窗口的重传机制和之前的超时重传机制也有所不同。滑动窗口中,如果某一个数据真的丢了(超过时间没有收到),接收方会给发送方发送的每一个不是丢失的数据发送的确认号都是丢失数据的确认号。当接收端接收到三次这个ACK时,会重新对这个ACK的数据进行重新发送。这种机制叫做高速重发机制,也称快重传。

例如:

  • 当某一段报文段丢失之后 , 发送端会一直收到 1001 这样的 ACK, 就像是在提醒发送端 " 我想要的是 1001" 一样
  • 如果发送端主机连续三次收到了同样一个 "1001" 这样的应答 , 就会将对应的数据 1001 - 2000 重新发送
  • 这个时候接收端收到了 1001 之后 , 再次返回的 ACK 就是 7001 ( 因为 2001 - 7000) 接收端其实之前就已 经收到了, 被放到了接收端操作系统内核的接收缓冲区。

思考1:有了快重传,为什么还需要超时重传

其实,超时重传是一种兜底策略。试想,如果所发送的数据小于3次时,即使数据丢失也引发不了块重传,此时还是需要超时重传进行解决。同时,如果是最后一个数据丢了,也是无法引发快重传的。

7、流量控制

接收端处理数据的速度是有限的 . 如果发送端发的太快 , 导致接收端的缓冲区被打满 , 这个时候如果发送端继续发送 , 就会造成丢包, 继而引起丢包重传等等一系列连锁反应 . 因此TCP 支持根据接收端的处理能力 , 来决定发送端的发送速度 . 这个机制就叫做 流量控制 (Flow Control) ;
  • 接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 "窗口大小" 字段, 通过ACK端通知发送端;
  • 窗口大小字段越大, 说明网络的吞吐量越高;
  • 接收端一旦发现自己的缓冲区快满了, 就会将窗口大小设置成一个更小的值通知给发送端;
  • 发送端接受到这个窗口之后, 就会减慢自己的发送速度;
  • 如果接收端缓冲区满了, 就会将窗口置为0; 这时发送方不再发送数据, 但是需要定期发送一个窗口探测数
  • 据段, 使接收端把窗口大小告诉发送端.

计算机网络---传输层(tcp、udp)_第13张图片

注意:实际上接收端和发送端第一次“协商”窗口大小是在三次我说的额过程中。三次握手建立连接时,SYN包中就包含了窗口大小。

8、拥塞控制

虽然 TCP 有了滑动窗口这个大杀器 , 能够高效可靠的发送大量的数据 . 但是如果在刚开始阶段就发送大量的数据 , 仍然可能引发问题. 因为网络上有很多的计算机, 可能当前的网络状态就已经比较拥堵 . 在不清楚当前网络状态下 , 贸然发送大量的数据 , 是很有可能引起雪上加霜的. TCP引入 慢启动 机制 , 先发少量的数据 , 探探路 , 摸清当前的网络拥堵状态 , 再决定按照多大的速度传输数据 ;

计算机网络---传输层(tcp、udp)_第14张图片

为了解决这个问题,引入了拥塞窗口的概念。开始发送数据的时候,拥塞窗口定义为1,每收到一个ACK拥塞窗口+1,每次发送数据的时候将拥塞窗口和主机端反馈的窗口大小做比较,取最小的作为实际发送的窗口大小。

但是,这样的拥塞窗口增长速度是指数级别的,。慢启动只是启动时速度慢,但是增长速度非常快。为了不增长的那么快, 因此不能使拥塞窗口单纯的加倍. 此处引入一个叫做慢启动的阈值。当拥塞窗口超过这个阈值的时候, 不再按照指数方式增长, 而是按照线性方式增长。

计算机网络---传输层(tcp、udp)_第15张图片

  • TCP开始启动的时候, 慢启动阈值等于窗口最大值;
  • 在每次超时重发的时候, 慢启动阈值会变成原来的一半, 同时拥塞窗口置回1;
少量的丢包 , 我们仅仅是触发超时重传 ; 大量的丢包 , 我们就认为网络拥塞 ;
TCP 通信开始后 , 网络吞吐量会逐渐上升 ; 随着网络发生拥堵 , 吞吐量会立刻下降 ; 拥塞控制, 归根结底是 TCP 协议想尽可能快的把数据传输给对方 , 但是又要避免给网络造成太大压力的折中方案 .

你可能感兴趣的:(计算机网络)