端口号
端口号标识了一个主机上进行通信的不同的用于程序
在TCP/IP协议中,用 “源IP”、“源端口号”、“目的IP”、“目的端口号”、“协议号” 这样一个五元组来标识一个通信(可以通过 netstat -n 语句查看)
认识知名端口号
0 - 1023: 知名端口号。HTTP、FTP、SSH 等这些广为使用的应用层协议, 他们的端口号在默认情况下都是固定的
- ssh 服务器,使用 22 端口号
- ftp 服务器,使用 21 端口号
- telnet 服务器,使用 23 端口
- http 服务器,使用 80 端口
- https 服务器,使用 443 端口
1024 - 65535: 操作系统动态分配的端口号(客户端程序的端口号,就是由操作系统从这个范围分配的)
UDP 协议
协议格式
- 16位源端口号/目的端口号:表示数据从哪个进程来,到哪个进程去
- 16位 UDP 长度:表示整个数据报(UDP首部+UDP数据)的最大长度
- 16位UDP校验和:用于校验收到的数据和发送的数据是否一致
UDP 的特点
UDP传输的过程类似于寄信
- 无连接:只需要知道对方的IP和端口号,就可以直接发送数据,不需要建立连接
- 不可靠:没有确认机制和重传机制;如果因为网络故障该段无法发到对方,UDP协议层也不会给应用层返回任何错误信息
- 面向数据报:不能灵活的控制读写数据的次数和数量。应用层交给UDP多长的报文,UDP原样发送,既不会拆分,也不会合并
- 有最大传输长度限制:UDP报文头部中有一个数据报长度字段,最大数字是65535字节,限制了一个完整 UDP报文的长度不能超过64k,不适合传输大数据
UDP 缓冲区
- UDP 没有真正意义上的发送缓冲区。调用 sendto 会直接交给内核,由内核将数据传给网络层协议进行后续的传输动作
- UDP 具有接收缓冲区。但是这个接收缓冲区不能保证收到的 UDP 报的顺序和发送 UDP 报的顺序一致;如果缓冲区满了,再到达的UDP数据就会被丢弃
TCP 协议
TCP 协议格式
解析:
- 16位源端口号/16位目的端口号:表示数据从哪个进程来,到哪个进程去
- 32位序号/32位确认序号:实现确认应答机制和超时重传机制
- 4位首部长度:表示该 TCP 头部长度(以4个字节位单位),TCP头部的最大长度是60字节
- 6位保留位:预留,用于后序扩展
- 6位标志位:URG、ACK、PSH、RST、SYN、FIN
具体含义:
URG:紧急指针是否有效
ACK:确认号是否有效
PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走
RST::对方要求重新建立连接,把携带RST标识的称为复位报文段
SYN:请求建立连接,把携带SYN标识的称为同步报文段
FIN:终止连接,把携带FIN标识的为结束报文段
- 16位窗口大小:用于实现滑动窗口机制
- 16位校验和:用于校验收到的数据和发送的数据是否一致
- 16位紧急指针:标识紧急数据
确认应答机制
TCP将每个字节的数据都进行了编号,即序列号:
每一个ACK都带有对应的确认序号,意思是告诉发送者,我已经受到了哪些数据,下次你从哪里开始发
超时重传机制
超时重传有两种可能:数据报丢了或者ACK丢了
- 主机A给主机B发送数据之后可能因为种种原因,数据没有到达主机B
- 如果主机A在一定时间间隔内没有收到主机B发来的ACK,就会进行重发
如果是ACK丢了 此时,主机A一直收不到主机B的ACK,就会进行重传, 那么主机B就会收到很多重复的数据,那么TCP协议需要能够识别出哪些包是重复的并且去掉,此时利用序列号和确认序号就可以达到去重的效果。
确认序号表示告诉发送方,前面的数据都已经正常接收了。比如主机A收到1001,就表示1-1000之间的数据已经成功传输。
注意: Linux中超时以500ms(时间不一定,也可以改)为一个单位进行控制,每次判定超时重发的时间都是500ms的整数倍
- 重发一次仍没有收到回应,那么需要等待2*500ms才会再次进行重传
- 以此类推,超时时间间隔以指数形式增长
- 累计到一定次数后,会强制关闭连接
连接管理机制(重要)
正常情况下,TCP要要经过三次握手建立连接,四次挥手断开连接 上图可以这么理解: 客户端:咱建立连接吧!可好? 服务器:好啊好啊 客户端:行!
客户端和服务器开始传输数据
客户端:我这边没啥了,咱关闭连接吧 服务器:好,我看看我这边还有啥 服务器:我这边也没数据了,咱可以关闭连接了 客户端:好的
滑动窗口
确认应答机制中,每发一次数据,都要等待一个ACK,发送方收到ACK之后,才可以发送下一个数据。这样做有一个缺点:性能差,耗时
那么可以一次发送多条数据,就会大大提高性能了。
- 窗口大小指的是无需等待确认应答就可以继续发送数据的最大值。上图的窗口大小是4000个字节
- 发送前四个段的时候,不需要等待任何ACK,直接发送
- 收到第一个ACK后,窗口向后移动,继续发送第五个段的数据
- 依次类推,窗口就像是在滑动一样向后移
- 操作系统内核为了维护这个滑动窗口,需要开辟发送缓冲区来记录当前还有哪些数据没有应答;只有确认应答过的数据,才能从缓冲区删掉
- 窗口越大,则网络的吞吐率就越高,性能就越好
如果出现丢包,重传有两种情况: 情况一:ACK丢了 这种情况下,ACK丢失无所谓,可以通过后面的ACK进行确认。
情况二:数据包丢了
- 当某一段报文段丢失之后,发送端会一直收到 1001 这样的ACK,就像是在提醒发送端 “我想要的是 1001” 一样
- 如果发送端主机连续几次收到了同样一个 “1001” 这样的应答,就会将对应的数据 1001 - 2000 重新发送
- 这个时候接收端收到了 1001 之后,再次返回的ACK就是7001了(因为2001 - 7000)接收端其实之前就已经收到了,被放到了接收端操作系统内核的接收缓冲区中
流量控制
接受端处理数据的速度是有限的。如果发送端发的太快,导致接收端的缓冲区满了,这个时候发送端继续发送,就会造成丢包,继而引起丢包重传等待一系列连锁反应。
因此TCP支持根据数据段的接受能力,来决定发送端的发送速度,这个机制就叫流量控制。
过了重发时间后还没有收到窗口更新的通知,发送端会发送一个小的窗口探测包(用来告诉发送端,接受端的剩余窗口大小)
拥塞控制
虽然有了滑动窗口,但是如果在刚开始就发送大量的数据,仍然可能引发问题。
为解决这一问题,TCP引入“慢启动机制”,先发少量的数据,摸清楚当前网络拥堵状态,再决定按照多大的速度传输数据
- 此处引入一个概念为拥塞窗口
- 发送开始的时候,定义拥塞窗口大小为1
- 每次收到一个ACK应答,拥塞窗口加1
- 每次发送数据包的时候,将拥塞窗口和接受端主机反馈的窗口大小做比较,取较小的值作为实际发送的窗口
延迟应答
如果接受数据的主句立刻返回ACK应答,这个时候返回的窗口可能比较小
假设接收端缓冲区为1M, 一次收到了500K的数据
如果立刻应答, 返回的窗口就是500K
但实际上可能处理端处理的速度很快, 10ms之内就把500K数据从缓冲区消费掉了
在这种情况下, 接收端处理还远没有达到自己的极限, 即使窗口再放大一些, 也能处理过来
如果接收端稍微等一会再应答,比如等待200ms再应答,那么这个时候返回的窗口大小就是1M
窗口越大,网络吞吐量越大,传输效率就越高
但是也不是所有的包都延迟应答,有限制的
数量限制: 每隔N个包就应答一次;
时间限制: 超过最大延迟时间就应答一次
捎带应答
在延迟应答的基础上,发现很多情况下,客户端服务器在应用层也是“一发一收”的,意味着客户端给服务器说了“How are you?”,服务器也会给客户端回一个“Fine.”
那么这个时候ACK就可以搭顺风车,和服务器的回应一起回给客户端
这样一来就减少了传输数据包的个数,降低了通信成本,提高了效率
面向字节流
三次握手成功后,通信双方都会在各自内核里创建一个发送缓存区和一个接受缓冲区。
发送端发送的数据的时候,会先调用相应函数把数据放在发送缓冲区,数据发送成功的时间有内核决定
接受端收到数据后,先把数据放在接受缓冲区,再调用相应方法读取数据
粘包问题
- 首先要明确,粘包问题中的 "包" , 是指的应用层的数据包
- 在TCP的协议头中, 没有如同UDP一样的 "报文长度" 这样的字段,但是有一个序号字段
- 站在传输层的角度,TCP是一个一个报文过来的,按照序号排好序放在缓冲区中
- 站在应用层的角度,看到的只是一串连续的字节数据
- 那么应用程序看到了这么一连串的字节数据,就不知道从哪个部分开始到哪个部分,是一个完整的应用层数据包,就会造成粘包问题
对于UDP协议来说, 是否也存在 “粘包问题” 呢?
对于UDP,如果还没有上层交付数据,UDP的报文长度仍然在
同时,UDP是一个一个把数据交付给应用层,就有很明确的数据边界
站在应用层的角度,使用UDP的时候,要么收到完整的UDP报文,要么不收
怎么解决粘包问题呢?有两种方法:
TCP异常情况
-
进程终止:进程终止会释放文件描述符,仍然可以发送FIN。和正常关闭没有什么区别(仍然会进行四次挥手且可以执行完毕) -
机器重启:和进程终止的情况相同(若四次挥手还没有执行完毕,机器就已经关闭了,发送端会重传几次,几次得不到回应就会释放资源) -
机器掉电/网线断开:接收端认为连接还在,一旦接收端有写入操作,接收端发现连接已经不在了,就会进行 reset。即使没有写入操作,TCP自己也内置了一个保活定时器,会定期询问对方是否还在,如果对方不在,也会把连接释放 假设主机A和主机B,主机A出现掉电/网线断开情况,分两种情况:
若主机B是发送方:发送数据后没有收到ACK,会触发超时重传机制,达到一定次数后,会尝试重新建立连接(使用6位标识符里的RST),得不到会议就会释放资源
若主机B是接受方,TCP总内置了“保活机制”--发送一个保活探测数据包,要求对方进行响应,若多次无响应,则认为连接断开
TCP和UDP的区别
- UDP无连接,TCP有连接
- UDP属于不可靠传输,TCP属于可靠传输
- UDP面向数据报,TCP面向字节流
综上所述: UDP的效率要求高,但对可靠性要求相对来说比较低 TCP的效率要求低,但对可靠性要求相对来说比较高
注意:TCP和UDP可以同时绑定一个端口,但是一个端口不能在同一时刻被TCP或UDP绑定两次
|