计算机网络 —— 传输层详解

端口号

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

在TCP/IP协议中,
通过 “源IP”, “源端口号”, “目的IP”, “目的端口号”, “协议号” 这样一个五元组来标识一个通信。

额外要注意的是一个端口只能bind一个进程,然后一个进程可以bind多个端口号。
进程就像是人,端口号就像是手机,一个手机只能被一个人用来通信,然后一个人却可以同时使用多个手机及进行通信。

端口号划分

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

注意 平时写程序使用端口时候要避开这些知名端口好,以免发生冲突。
该命令用于查看知名端口号

cat /etc/services

UDP协议

Internet 协议集支持一个无连接的传输协议,该协议称为用户数据报协议(UDP,User Datagram Protocol)。UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP
数据包的方法。

UDP协议格式

源端端口对端端口
数据报长度校验和
数据数据(报头8字节 (2字节 * 4)数据不超64k-20-8)

格式解析

  • 16位源端端口和对端端口 : 描述端与端之间的通信
  • 数据报长度:限制了UDP报文的总长度(64K)
  • 校验和:采用二进制反码求和算法,确保数据收发无误
  • 数据:发送的数据
  • 二进制反码求和简介: 从报文开始的每个字节进行取反相加,高出16位截断高位, 与低16位继续相加,得到校验和。

UDP协议特性解析

无连接,不可靠,面向数据报

  • 无连接: 知道对端的IP和端口号就直接进行传输, 不需要建立连接
  • 不可靠: 传输层不保证数据安全有序到达对面 (程序员在应用层进行包序管理)
  • 面向数据报: 有最大小限制的传输方式 数据大小不能大于64k-8-20字节

UDP其他注意事项

  1. udp的数据传输是整条交付的,因此缓冲区要足够大(64k即可)。
  2. sendto将数据放入缓冲区之后直接封装头部,进行发送。
  3. recvfrom总是接收一条完整的数据不能接收半条或者多条(否则报错)。
  4. 由于udp不进行包序管理因此数据分包发送时需要程序员在应用层进行分包操作。

UDP不粘包

发送端可以是一K一K地发送数据,而接收端的应用程序可以两K两K地提走数据,当然也有可能一次提走3K或6K数据,或者一次只提走几个字节的数据。

也就是说,应用程序所看到的数据是一个整体,或说是一个流(stream),一条消息有多少字节对应用程序是不可见的,因此TCP协议是面向流的协议,这也是容易出现粘包问题的原因。而UDP是面向消息的协议,每个UDP段都是一条消息,应用程序必须以消息为单位提取数据,不能一次提取任意字节的数据, 这一点和TCP是很不同的。怎样定义消息呢?可以认为对方一次性write/send的数据为一个消息,需要明白的是当对方send一条信息的时候,无论底层怎样分段分片,TCP协议层会把构成整条消息的数据段排序完成后才呈现在内核缓冲区。

UDP使用注意事项

我们注意到, UDP协议首部中有一个16位的最大长度. 也就是说一个UDP能传输的数据最大长度是64K(包含UDP首 部). 如果我们需要传输的数据超过64K, 就需要在应用层手动的分包, 多次发送, 并在接收端手动拼装。

基于UDP的应用层协议(了解)

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

当然, 也包括你自己写UDP程序时自定义的应用层协议;

TCP协议

TCP协议格式

协议格式如图所示:
在这里插入图片描述
协议解析

  • 16位源端端口号/16位对端端口号: 描述的端与端之间的通信。
  • 32位序号/32位确认序号: 实现的tcp的包序管理——数据总是有序交付给上层
  • 4位头部长度: 以四字节为单位描述tcp报头长度(tcp包头最小20 最大 60byte)
  • 六位保留:
  • 六位标志位:
    URG:紧急指针(urgent pointer)有效。
    ACK:确认序号有效。
    PSH:接收方应该尽快将这个报文交给应用层。
    RST:重置连接。
    SYN:连接建立请求,发起一个新连接。
    FIN:断开连接,释放一个连接。
  • 16位窗口大小: 实现滑动窗口机制,进行流量控制,防止缓冲区满溢从而丢包。
  • 16位校验和: 二进制反码求和,检验数据收发一致。
  • 16位紧急指针: 发送带外数据。与普通数据不同的通道独立传送给用户(迅速通知)。
  • 0~40字节的选项数据: 用于协商(MSS协商)等以及描述一些信息。

TCP协议特性解析

面向连接,可靠传输,面向字节流。

面向连接

面向连接意味着服务端与客户端双方建立连接之后才可以进行通信,这就像是打电话一样必须电话通了才可以进行交流。tcp有自己的连接管理,下面对tcp的连接管理进行解析。

三次握手建立连接

由于tcp是面向连接的,因此收发数据前必须双方建立连接才可以。tcp建立连接的过程叫做三次握手。过程如下:

  1. 客户端新建套接字,向服务端发起连接请求
    具体过程: 客户端新建套接字,向服务端发送SYN建立连接请求,然后进入SYN_SENT状态。
  2. 服务端通过监听套接字新建双方连接的套接字并进行回复
    具体过程: 服务端收到SYN请求之后,通过监听套接字新建一个供双方进行通信的套接字,并向客户端发送SYN连接+ACK确认回复,然后进入SYN_RCVD状态。
  3. 客户端收到回复,进行进入就绪状态并向服务端发送自己已经准备就绪。
    具体过程: 客户端收到SYN+ACK回复之后,向服务端发送ACK确认回复,进入ESTABLISHED就绪状态。
  4. 服务端收到回复之后,也进入就绪状态。
    具体过程: 服务端收到ACK确认回复之后,进入ESTABLISHED状态。

上述过程中,每一个状态都是为了等待该状态所需要的回复
经过上面的三次信息的接收与发送之后,利用tcp通信的双方就建立好了可靠稳定的连接。

TIP: 为什么要三次握手而不是两次或者四次? 三次握手失败怎么处理?

  1. 简单来说就是两次不安全,四次太多余
    两次就能建立连接,如果客户端发送多次SYN则都会建立连接浪费资源
    如果客户端发送连接之后退出,服务端的新建套接字就会占用资源(保活机制)
  2. 1)没收到SYN什么都不做。2)SYN+ACK/ACK丢失,超时后发送RST重置连接报文,释放新建的套接字(等待重新建立连接)。
四次挥手断开连接

也是因为tcp是面向连接的,因此断开连接也需要双方都确定断开才可以,不然的话就会有数据丢失等一系列的危险。tcp断开连接的过程叫做四次挥手。过程如下:

  1. 客户端向服务端发送结束连接的请求。
    具体过程: 客户端向服务端发送FIN包,关闭自己的写端,表明不再发送数据,进入FIN_WAIT1状态。
  2. 服务端收到请求,对客户端发送确认请求。
    具体过程: 服务端收到FIN包,向客户端发送ACK确认回复,进入CLOSED_WAIT状态。
  3. 客户端收到服务端的确认回复。
    具体过程: 客户端收到ACK确认回复之后进入FIN_WAIT2状态。
  4. 服务端和客户端处理完双方之间的其他信息之后,向客户端发送断开连接请求。
    具体过程: 双方处理完其他任务之后,服务端向客户端发送FIN包,
  5. 客户端收到请求之后,向服务端发送确认回复,客户端等待一段时间之后CLOSED。
    具体过程: 客户端收到FIN包,向服务端发送ACK确认回复,进入TIME_WAIT状态。等待一段时间之后CLOESD。
  6. 服务端收到确认回复之后,CLOSED释放资源。
    具体过程: 服务端收到ACK确认回复之后CLOSED。

注意

  • FIN-WAIT-1阶段,即半关闭阶段 :并且停止在客户端到服务器端方向上发送数据,但是客户端仍然能接收从服务器端传输过来的数据。
  • ACK回复表示的是接收到了对方发送的请求。
  • 这里不发送的是正常连接时传输的数据(非确认报文),而不是一切数据,所以客户端仍然能发送ACK确认报文

前两次挥手"既让服务器端知道了客户端想要释放连接,也让客户端知道了服务器端了解了自己想要释放连接的请求。于是,可以确认关闭客户端到服务器端方向上的连接了。
后“两次挥手”既让客户端知道了服务器端准备好释放连接了,也让服务器端知道了客户端了解了自己准备好释放连接了。于是,可以确认关闭服务器端到客户端方向上的连接了,由此完成“四次挥手”。

TIP
为什么挥手是四次而不是三次?
FIN请求代表不再写数据,就是不再发送数据,而不代表不在接收数据了(有可能继续接处理一些其他请求), 只有两边都FIN之后才代表两边可以断开连接了,类似于管道全部关闭写端,读完数据后返回一样。

在这里插入图片描述

TIME_WAIT的意义?
假设无tine_wait, 当被动关闭方没有收到最后一次的ACK时,就会出现两种问题。

  1. 新启动的客户端绑定地址信息,收到重传的FIN,影响新连接。
  2. 新启动的客户端如果恰好向被动关闭方发送SYN, 由于被动关闭方需要ACK而不是SYN,就会发送RST

因此综上, 当客户端发出最后的ACK确认报文时,并不能确定服务器端能够收到该段报文。所以客户端在发送完ACK确认报文之后,会设置一个时长为2MSL的计时器。防止出现以上情况,时间大小时2MSL,在这2MSL中处理相关问题。
MSL指的是Maximum Segment Lifetime:一段TCP报文在传输过程中的最大生命周期。

2MSL即是服务器端发出为FIN报文和客户端发出的ACK确认报文所能保持有效的最大时长。

具体操作

  1. 服务器端在1MSL内没有收到客户端发出的ACK确认报文,就会再次向客户端发出FIN报文;
  2. 如果客户端在2MSL内,再次收到了来自服务器端的FIN报文,说明服务器端由于各种原因没有接收到客户端发出的ACK确认报文。客户端再次向服务器端发出ACK确认报文,计时器重置,重新开始2MSL的计时;
  3. 否则客户端在2MSL内没有再次收到来自服务器端的FIN报文,说明服务器端正常接收了ACK确认报文,客户端可以进入CLOSED阶段,完成“四次挥手”。

TIP

  1. 为什么存在大量time_wait状态的套接字?
    time_wait主动关闭方出现, 说明该主机大量的关闭了连接, 常见于一些爬虫服务器。
    解决方式:调整time_wait时间 2. 更改套接字选项setsockopt ,开启地址重用(针对关闭的几个状态)

  2. 为什么存在大量close_wait状态的套接字?
    close_wait是被动关闭方收到fin请求后的状态,如果大量出现,可能是被动关闭方忘记最后一步断开连接后调用close释放资源。

  3. 为什么时2MSL时间?
    一个MSL是一个报文的生存周期,因为time_wait状态涉及FIN和ACK两个报文(具体每个MSL时间都做了什么看上面关于MSL描述)

  4. shutdown/close关闭套接字区别
    前者关闭读写端不释放资源,后者关闭释放资源

连接保活机制

tcp通信中,若两端长时间没有数据往来,则这时候每隔一段时间,服务端回向客户端发送一个保活探测数据报,要求客户端回复,若来凝结多次没有收到响应,则认为连接断开。

以下数据均为默认数据,通过设置套接字选项可配置 socketopt

  • 长时间: 7200s
  • 每隔一段时间: 75s
  • 连续多次:9次

可靠传输

面向连接

面向连接是可靠传输的前提

确认应答机制,超时重传机制与数据有序完整交付

可靠传输简单来说就是数据可以安全到达对面保证数据成功接收。
主要从是从下面几方面实现:

  • 面向连接
  • 确认应答机制 发送数据后要求对方进行回复,保证数据成功到达,通过序号与确认序号实现
  • 超时重传机制 发送数据等待响应超时之后,认为数据丢失,进行重新传输。动态200ms时间 会随对方的响应时间进行调整
  • 通过序号与确认序号进行数据的有序交付
  • 通过校验和字段检验数据的一致性

在这里插入图片描述

我们以一次完整的数据通信来对上面的机制进行讲解。
seq 本条数据的起始序号
ack 对方发送数据的确认序号,告诉对方收到了数据
注意 ack确认序号与ACK确认回复标志位使两个概念。下面用大小写进行区分

  1. 客户端向服务端发起连接请求 发送SYN建立连接 报文中 seq=0(实际是默认随机值)ack=0 进入 SYN_SENT 状态。
  2. 服务端收到SYN之后, 发送ACK+SYN 报文中 seq=0 ack=1 进入SYN_RCVD状态。
  3. 客户端收到ACK+SYN, 向服务端发送ACK 报文中seq=1 ack=1 进入ESTABLISHED。
  4. 服务端收到ACK进入ESTABLISHED状态,至此两边就开始稳定的连接了。
  5. 客户端向服务端发送长度1024字节数据,报文中seq=1,ack=1,len=1024
  6. 服务端收到数据进行回复,报文中,seq=1,ack=1025,len=0(假设只进行确认回复)
  7. 客户端再次向服务端发送1024字节数据, 此时报文中seq=1025,ack=1,len=1024
  8. 服务端向客户端确认回复, 报文中seq=1,ack=2049,len=0,

上面的过程可以分成两个小过程,

  • 三次握手建立连接,双方协商起始序号(例子为0)确认序号为对方发送的其实起始序号加1
  • 数据通信 确认序号是对方的起始序号加长度告诉对方这个确认序号之前的数据已经全部收到。

基于上面的性质, 我们可以很容易理解确认应答机制和超时重传机制。
确认应答机制的实现就是当发送端没有收到接收方的ACK确认回复的时候,那么就认为接收方没有收到这条数据,等到一定时间以后,超时重传机制就会重新发送这条数据。
通过ack与seq的确认,就可以实现数据的有序交付
在接受方的缓冲取会根据数据的seq来对数据进行排序,保证数据有序交付。

例子

  1. 数据来连续发送三条时,第一条数据直接丢失,接收方就不会对二三条进行ACK回复,那么发送方就会重新发送。
  2. 数据来连续发送三条时,第一条确认回复丢失,但是数据收到了,接收方正常回复,发送方不再重发ack之前的数据。
  3. 因为网络原因,数据乱序到达,接收方根据数据的起始序号在接收缓冲区进行包序管理。
其他丢包问题处理

主要阐述两个问题

  1. 发送方发送数据过快,接收方来不及处理,导致接收缓冲取满溢,之后的数据被丢弃。
  2. 发送方发送数据过多,此时网络较差,导致大量丢包重传。

下面对如何解决这两个问题进行说明。

滑动窗口机制

TCP滑动窗口技术通过动态改变窗口大小来调节两台主机间数据传输。每个TCP/IP主机支持全双工数据传输,因此TCP有两个滑动窗口:一个用于接收数据,另一个用于发送数据。

发送窗口表示一次最多可以向接收方发送多少数据,接收窗口表示还可以最多一次接收多少数据。

窗口其实是通过前沿和后沿在缓冲区中括出的。因此窗口大小不能超过接收缓冲区大小。

缓冲区就像是一个循环队列,数据按序接收之后,先进先出。前沿和后沿只是一个序号并不是内存单元的编号。

TIP

  • MSS: 最大数据段大小,由双方进行协商(保留位)取两者较小的值作为最大数据段,每条发送的数据大小不能超过这个值。
  • 滑动窗口有一个前沿和后沿,前沿 - 后沿 = 窗口大小。
  • 窗口大小不能超过缓冲取的大小。
  • 发送窗口后沿:发送数据的起始序号,后沿的移动取决于是否收到确认回复。
  • 发送窗口前沿:根据接收方窗口大小进行变化。保证两方窗口大小相同。
  • 接收方后沿:接收数据的起始序号,后沿的移动取决于是否从缓冲区取出了数据。
  • 接收方前沿:根据接受缓冲取的剩余空间进行计算得到。

==滑动窗口机制允许发送方根据窗口大小以及MSS大小来连续发送多条数据。==同时也制定了多条协议来进行数据丢失的处理。下面列举几种。

  • 停等协议:发送数据得到回复才可发送下一条数据。
  • 回退n步协议:一条数据丢失了则重新发送这条数据及这条数据之后的所有数据。
  • 选择重传协议:一条数据丢失,则只发送这条丢失的数据(网络状态良好)
拥塞控制

拥塞控制解决的当网络较差的时候,发送数据过多导致的数据重传问题。
拥塞控制通过网络探测来确定当前是否可以发送多条数据,他是用一种慢启动快增长的方式来进行数据传输。简单来说就是,每次开始发送数据的时候,
举例说明
第一次发送1条数据,收到回复,此时验证网络良好。
第二次发送2条数据,收到回复,此时验证网络良好。
第三次发送4条数据,收到回复,此时验证网络良好。
第四次发送8条数据,其中有两条没有收到回复,此时验证网络不好。 那么下次重新从1开始。
第五次发送1条数据,收到回复,此时验证网络良好。
第六次发送2条数据,收到回复,此时验证网络良好。

网络良好时,发送数据的大小并不能无限增长,最大不能超滑动窗口大小,滑动窗口的大小是一个阈值。

提高传输性能的方式
快速重传协议

概念
发送端连续发送多条数据,但是接收端接收到的不是后沿数据,认为后沿数据丢失,不会向发送方进行确认回复,然后会进行三次间隔的重传请求。
发送方收到三次请求后会向接收方重新传输该条数据。

问题
为什么要进行三次间隔重传请求?
避免网络原因导致的数据延迟到达。若数据在三次请求期间到达了,则接收方没有收到三次完整的请求,不用重传。
快速重传协议的优点?
避免发送端的超时重传,提高效率。

延迟应答协议

概念
接收方接收数据之后,并不立即进行确认回复,而是等待一段时间之后在回复。
优点
在接收方等待的这一段时间内,如果缓冲区的数据被取走了,那么窗口大小不会减小,甚至可能增大,发送方就可以发送更大的数据了。

捎带应答协议

概念
接收方接受数据之后,进行确认回复,在即将发送的数据头部中进行上一条数据的确认回复。
优点
确认回复就是在报头中修改确认序号,进行回复,使用捎带应答可以减少一个空的报头的响应占据带宽。

面向字节流

tcp是一种字节流传输服务 - 面向连接的,有序的一种最小以字节为传输单元的传输服务。

为什么说tcp可以以字节为传输单元呢?

发送端send发送数据的时候, 并不会将数据直接进行发送,而是先将数据放到发送缓冲区中,选择合适的时候从缓冲区中取出合适大小的数据进行封装发送。

接收端recv接收数据的时候, 并不会一条一条的向上交付,而是会将接收到的数据放到接收缓冲区中取出指定长度的数据进行交付。

面向字节流优缺点

优点:
传输灵活,大量小数据可以合并成一整条数据进行交付,减少io次数,接收方可以根据需要进行数据的取出。
缺点:
tcp交付的数据可能不是一条数据,而是多条数据混合的,导致上层按照一条数据进行处理,需要解决这种粘包问题。

粘包解决方案
  • 每条数据以特殊字符进行间隔 – 缺点 数据中有特殊字符需要转义处理(url)
  • 数据定长传输 – 传输大量小数据时 ,需要填补空位,会造成资源浪费
  • 应用层协议头部定义数据长度 – http协议为典型例子

以http和udp解决粘包问题进行说明
http头部以\r\n\r\n表示结束并在头部中通过content-length定义了正文的长度
udp在传输层中解决的,头部定长八个字节,头部中定义了数据报文长度。

其他

netstat

netstat是一个用来查看网络状态的重要工具.
语法:netstat [选项]
功能:查看网络状态

n 拒绝显示别名,能显示数字的全部转化成数字
l 仅列出有在 Listen (监听) 的服務状态
p 显示建立相关链接的程序名
t (tcp)仅显示tcp相关选项
u (udp)仅显示udp相关选项
a (all)显示所有选项

pidof

在查看服务器的进程id时非常方便.
语法:pidof [进程名]
功能:通过进程名查看进程id

TCP异常情况

进程终止: 进程终止会释放文件描述符, 仍然可以发送FIN. 和正常关闭没有什么区别.
机器重启: 和进程终止的情况相同.
机器掉电/网线断开: 接收端认为连接还在, 一旦接收端有写入操作, 接收端发现连接已经不在了, 就会进行reset. 即
使没有写入操作, TCP自己也内置了一个保活定时器, 会定期询问对方是否还在. 如果对方不在, 也会把连接释放.
另外, 应用层的某些协议, 也有一些这样的检测机制. 例如HTTP长连接中, 也会定期检测对方的状态. 例如QQ, 在QQ断线之后, 也会定期尝试重新连接

TCP与UDP简单对比

TCP用于可靠传输的情况, 应用于文件传输, 重要状态更新等场景;
UDP用于对高速传输和实时性要求较高的通信领域, 例如, 早期的QQ, 视频传输等. 另外UDP可以用于广播。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值