传输层
- 服务器和端口的关系
- 为网络中计算机提供服务的服务,一旦启动就会使用TCP或UDP的某个端口侦听客户端的请求。
- 客户端通过IP地址定位服务器, 通过协议和端口号定位服务器上的服务.
防火墙
- 配置服务器的防火墙
- 配置路由器的防火墙
- 本质
- 防火墙的本质就是控制TCP/UDP的某些端口的请求是否可以通过
- 防火墙只是限制进入防火墙的请求, 出去防火墙的请求不会控制
- 如果是主机主动发请求给服务器, 服务器需要判断主机的端口号和使用的协议是否允许通过.
- 如果是服务器A主动发给服务器B的请求, 因为是出去的流量是允许通过的, 此时服务器A和服务器B已经建立了连接. 这时候,服务器B给服务器A返回的数据是允许通过防火墙的.
1. TCP
-
Transmission Control Protocol : 传输控制协议
-
传输的数据叫做 段
-
MSL(Maximum Segment Lifetime) : TCP报文在Internet上的最长生存时间(通常是2分钟)
-
如果应用层需要传输的数据很大, 那么在传输层时候就会分片.
1. 因为如果不在传输层分片, 那么就会在网络层分片, 然后在数据传输过程中, 网络层分片后的某些数据包丢失, 要求tcp重传时候, 由于在网络层分片, 传输层(TCP)并不知道该重传什么位置的数据, 就只能重传整个数据包, 这样效率就有问题了. -
TCP 并没有提供任何机制,表示原始文件的大小,这由应用层的协议来规定。比如,HTTP 协议就有一个头信息Content-Length,表示信息体的大小。对于操作系统来说,就是持续地接收 TCP 数据包,将它们按照顺序组装好,一个包都不少。
-
面向字节流
-
TCP头部
- 固定部分(20字节, 通常都是20字节)
-
源端口号 :
- 2个字节 0 - 65535
- 客户端的端口号通常是随机生成的, 服务端的端口号通常是一个服务一直监听某个端口号.
-
目的端口号 :
- 2个字节 0 - 65535
- 客户端的端口号通常是随机生成的, 服务端的端口号通常是一个服务一直监听某个端口号.
-
序号 seq :
- 占4字节;
- 在传输过程中每个字节都有字节的都有自己的编号, 并且连续的字节编号是连续的.
- 在建立连接后, 序号代表这一次传递给对方的tcp数据部分的第一个字节的编号
-
确认号 ack:
- 占4字节;
- 在建立连接后, 确认号代表期望对方下一次传过来的tcp数据的第一个字节的编号.
-
数据偏移:
- 占 4 位, 需要将二进制转换成10进制之后的结果 * 4才能得到实际的首部的的长度(这里的长度包括可变部分).
- 0b0101 : 20 (最小值)
- 0b1111 : 60 (最大值)
- 占 4 位, 需要将二进制转换成10进制之后的结果 * 4才能得到实际的首部的的长度(这里的长度包括可变部分).
-
保留 :
- 占 6位.
-
URG : Urgent
- 占1位 当URG == 1时候, 紧急指针字段内的内容才有效, 表示当前报文段中有紧急数据, 需要优先尽快传送.
-
ACK : Acknowledgment
- 占1位 当ACK == 1时候, 确认号(ack)字段才有意义.
- 通常除了客户端那次发起连接的第一次握手时ACK == 0, 其余的时候ACK都是1.
- 三次握手中, 第一次 SYN = 1, ACK = 0; 第二次 SYN = 1, ACK = 1; 第三次 : SYN = 0, ACK = 1;
-
PSH :
- 占1位, 一般不用
-
RST :
- 占1位 当RST == 1时候, 表示连接中出现严重差错, 需要释放连接然后重新建立连接.
-
SYN :
- 占1位 当SYN == 1 时候, 表示请求建立连接的请求/.同意建立连接的回复.
- 通常在建立连接的第一次握手和第二次握手时候, SYN= 1, 其余时候 SYN = 0;
- 三次握手中, 第一次 SYN = 1, ACK = 0; 第二次 SYN = 1, ACK = 1; 第三次 : SYN = 0, ACK = 1;
-
FIN :
- 占1位 表示数据发送完毕, 要求释放连接.
- 通常四次挥手的第一次(请求断开连接方)和第三次(同意断开连接方)发送的数据中的FIN == 1, 其余时候的FIN = 0;
-
窗口:
- 占2字节;
- 这个字段有流量控制的功能, 用来告诉对方下一次允许发送的数据的大小(单位是字节)
-
检验和 :
- 伪首部 + 首部 + 数据部分计算得到
- 伪首部
1. 占用12个字节, 仅在计算检验和时候起作用, 不会传递给网络层
-
紧急指针:
- 保存数据长度 len, 表示tcp数据部分前len字节是紧急数据, 应该尽快传递.
- 当URG == 1时有效. 才有意义
-
- 可变部分
- 通常在建立连接和同意建立连接的报文中, 头部长度的32 字节. 其中固定部分长度20字节, 可变部分12字节.
- MSS(Max Segment Size) , 2 个字节. 表示传输层发送的每个数据包的最大可以发送的数据大小(理论上 : 1500(MTU ) - 20(IP头固定长度) - 20(TCP头部固定长度) = 1460, 但是实际上不是) 如果建立连接和同意建立连接的报文中的MSS不同, 就取比较小的值MIN(MSS_send, MSS_receive). 这里 如果MSS的值是1400, 而流量控制的滑动窗口大小是4200, 那么ARQ+窗口滑动的表现就是:每次流量控制客户端可以连续发送3大小是1400字节的数据包,然后服务端会回应一个ack包,. 然后发送端接着连续发送3大小是1400字节的数据包.
- window scale 2 个字节. 窗口缩放系数. 通常真正的窗口的大小 = 报文中的窗口 * window scale, 因为报文中的窗口大小只有两个字节, 所能表示的数子只能是 0 - 65535.
- 固定部分(20字节, 通常都是20字节)
-
特性:
-
可靠传输
1. ARQ : automatic repeat request : 自动重传请求 (效率比较低 被取代了)
当A发送m1后, B需要发送确认接收到m1消息给A, 然后A收到B发送的收到m1的消息后, 再发m2(图a: 无差错情况); 如果m1在发送过程中丢了, A在超时时间内没有收到B发送给A的确认消息时候, 将会重新发送m1给B(图b: 超时重传);如果m1的确认消息在发送过程中丢了, A在超时时间内没有收到B发送给A的确认消息时候, 将会重新发送m1给B, 此时B会收到两个m1, 这时候B会丢弃重复的m1, 并重新发送确认m1的消息(图a: 确认丢失); 如果m1的确认消息在发送过程中选择了较远的一条链路, A在超时时间内没有收到B发送给A的确认消息时候, 将会重新发送m1给B, 此时B会收到第二个m1时候, 选择了较近的一条链路发送m1的确认消息给A, 这时候A会收到两个m1 的确认消息, 此时A收到迟到的m1的确认消息时候, 什么也不做(图b: 确认迟到);- 连续ARQ协议+滑动窗口协议.
建立连接时, B告诉A接收窗口大小是400字节, A的发送窗口就是400字节. 假设显示每个包只能发送100字节, 那么A就是联系发送4个100字节的包, 当B收到第400字节的时候, 会给A发送确认包(连续ARQ), 让A 发送第401字节. 并设置发送窗口大小为400字节, 此时A窗口滑动400字节(窗口滑动)
1. t1时间, A和B建立连接, 并且B告诉A接收窗口的大小位400字节. A将发送窗口大小限制为400字节, 并且A和B将窗口滑动到发送缓存/接收缓存最开始的位置.假设每个序号的数据段的大小是100字节, 然后A开始给B发送数据, 由于限制了发送窗口的大小是400字节, 每个段的大小是100字节, 所以可以发送四次数据, seq分别是seq = 1, seq = 101, seq = 201, seq = 301; 2. t2时间, B接收到了A发送的四个数据, 然后B开始读取接收到的编号连续的数据, 并且将接收窗口向后滑动400字节, 然后发送确认收到数据的消息( ack = 401, 表示希望下次发送的数据序号从401开始), 并发送接收窗口的大小依然是400; 3. t3时间, A收到B发送的确认收到数据的消息,和窗口大小为400. 然后开始将发送窗口向后滑动400字节, 并将发送缓存窗口前边的数据部分清空, 然后发送400字节的数据seq分别是seq = 401, seq = 501, seq = 601, seq = 701; 但是此时601编号的数据再传输过程中丢失.- t4时间, B将接收缓存窗口前边的部分的数据清空. 然后B开始读取接收到的编号连续的数据, 发现收到了编号5, 6, 8的数据, 然后将接收窗向后移动到丢失的数据编号的位置, 然后发送确认收到数据的消息( ack = 601和已经收到第8个分组的边界, 表示希望下次发送的数据序号从601开始, 并且编号为701-800的数据已经收到了), 并发送接收窗口的大小是400;
- t5时间, A收到B发送的确认收到数据的消息,和窗口大小为400. 然后开始将发送窗口向后滑动200字节, 并将发送缓存窗口前边的数据部分清空, 然后发送300字节的数据seq分别是seq = 601, seq = 801, seq = 901; 此时窗口不在滑动.等待接收方的确认消息
- t6时间, B将接收缓存窗口前边的部分的数据清空. 然后B开始读取接收到的编号连续的数据, 将收到的601-700写入到对应的位置上, 然后写入801-900, 901-1000, 然后将接收窗向后移动400字节, 然后发送确认收到数据的消息( ack = 1001, 表示希望下次发送的数据序号从1001开始);
- t5时间点, 如果用到的sack 那么只会重发第7个分组, 如果不是sack(selective acknowledgment 选择性确认技术), 就会重发 第7个和第8个分组. sack 是将收到的分组的边界信息写入到tcp的可选部分.
- 上述传输过程如果一某个包一直发送失败, 在某些系统上, 如果重传失败超过5次, 就会发送reset报文(RST), 断开这次连接重新建立连接.
- 连续ARQ协议+滑动窗口协议.
-
流量控制
1. 控制发送方发送数据的速率, 让接收方有时间接收处理.
2. 如果接收方的缓存区已经满了, 但是发送方还是疯狂的发送数据, 此时接收只能丢掉收到的数据, 这是资源的浪费, 这就需要流量控制.
3. 原理:- 通过确认报文的窗口字段, 来控制发送方的发送速率.
- 发送方的发送窗口大小不能超过接收方给出的窗口大小.
- 当发送方收到接收窗口大小为0时候, 发送发会停止发送数据.
1. 如果接收方先给发送方发送了窗口为0的报文, 然后又给发送方发送了窗口200的报文, 但是后发送的报文丢失了, 这时候该如何处理这中情况.- 这种情况的解决方案是, 当发送方接收到接收方窗口为0的报文, 就会停止给接收方发送数据, 同时启动一个定时器, 每隔一定时间发个测试报文去询问接收方新的窗口大小, 如果回复的窗口大小还是0, 发送方就会刷新定时器.
-
拥塞控制
- 基础概念
-
cwnd 拥塞窗口, 根据网络环境, 发送方自己调整的.
-
rwnd 接收窗口, 由接收方告诉发送方
-
swnd 发送窗口
-
swnd = MIN(cwnd, rwnd) ;
-
慢开始
1. cwnd 初始值很小, 然后随着数据包被接收方确认, cwnd 不断增大(指数级增大) -
拥塞避免
- ssthresh( slow start threshold), 慢开始阈值. 当慢开始不断增大的值到达cwnd阈值后, 开始以线性方式缓慢增加(加法增加)
-
快速重传
- 接收方, 每收到一个时序的分组后, 就立即发出重复确认. 使发送方及时知道分组没有到达.
- 发送方, 只要连续收到三个重复确认(共四个相同的确认), 将立即重传对方尚未接收到的报文段.
-
快速恢复
- 当网络出现拥塞,就把ssthresh的值 * 0.5, 同时将cwnd值设置为ssthresh(乘以0.5以后的值), 然后开始执行拥塞避免算法(加法增大), 使拥塞窗口线性增大.
-
- 基础概念
-
建立连接
-
三次握手
- 原理 :
- 只有第一次和第二次握手时候, SYN = 1,
- 第一次握手时候, ACK = 0;
- 第三次握手之后, 客户端会在下一个包中发送http请求的数据(将http中的参数等信息都写在tcp的数据中)
- ack 就是对上次对方发来的seq的回应, 告诉对方 你上次发送的seq我收到了, 你该发送第 seqNO + lastPackageLen + 1 个数据了.
- CR 只会出现在 客户端发给服务端的seq中和服务端发给客户端的ack中, 同理SR 只会出现在服务端发给客户端的seq中和客户端发给服务器段的ack中.
- 客户端->服务端(第一次握手)
- SYN = 1; ACK = 0; seq = CR, ack = 0; len = 0;
- 告诉服务端seq的初始值(随即数值 CR),
- 没有tcp的数据部分, 只有tcp头, 协商的信息都在tcp头中.
- 头部32一般字节
- 交换一些信息 : MSS, 是否支持 SACK, Window scale,
- 服务端->客户端(第二次握手)
- SYN = 1; ACK = 1; seq = SR, ack = (CR + 1, 希望下次从第一个字节开始发送); len = 0;
- 告诉客户端seq的初始值(随机数值 SR)
- 没有tcp的数据部分, 只有头, 协商的信息都在tcp头中.
- 头部32一般字节
- 交换一些信息 : MSS, 是否支持 SACK, Window scale,
- 客户端->服务端(第三次握手)
- SYN = 0; ACK = 1; seq = CR + 1, ack = SR + 1; len = 0;
- 没有tcp的数据部分, 只有tcp头,
- 客户端->服务端(发送http请求)
- SYN = 0; ACK1; seq = CR + 1, ack = SR + 1; len = l1;
- 服务端->客户端(回复数据包1给客户端)
- SYN = 0; ACK1; seq = SR + 1, ack = CR + 1 + l1; len = l2;
- 服务端->客户端(回复数据包2给客户端)
- SYN = 0; ACK1; seq = SR + 1 + l2, ack = CR + 1 + l1; len = l3;
- 服务端->客户端(回复数据包3给客户端)
- SYN = 0; ACK1; seq = SR + 1 + l2 + l3, ack = CR + 1 + l1; len = l4;
- 服务端->客户端(回复数据包4给客户端)
- SYN = 0; ACK1; seq = SR + 1 + l2 + l3 + l4, ack = CR + 1 + l1; len = l5;
- 客户端->服务端(确认收到4个包)
- SYN = 0; ACK1; seq = CR + 1 + l1, ack = SR + 1 + l2 + l3 + l4 + l5 ; len = 0;
- 确认收到包消息, 没有数据部分.
- 原理 :
-
-
断开连接
- 客户端->服务端(第一次挥手)
- FIN = 1, ACK = 1;
- 表示自己已经没有数据要发送给对方了
- 服务端->客户端(第二次挥手)
- ACK = 1;
- 表示知道对方已经没有数据要发送给自己了
- 服务端->客户端(第三次挥手)
- FIN = 1, ACK = 1;
- 表示自己已经没有数据要发送给对方了
- 客户端->服务端(第四次挥手)
- ACK = 1;
- 表示知道对方已经没有数据要发送给自己了
- 断开连接时候, client 发送ACK后, 需要等待2MSL再关闭连接的原因
- 防止本次连接中产生的数据包误传到下一次连接中(当过个MSL后, 上次发送的报文段就已经失效了)
- 客户端->服务端(第一次挥手)
-
2. UDP
-
User Datagram Protocol 用户数据报协议
-
传输的数据叫做 段
-
UDP首部
- 固定长度8个字节
- 16位源端口号
- 受到长度限制, 端口号范围是 0 - 65535
- 客户端的端口是临时开启的随机端口
- 服务器是某个服务一直监听某给端口
- 16位目的端口号
- 受到长度限制, 端口号范围是 0 - 65535
- 客户端的端口是临时开启的随机端口
- 服务器是某个服务一直监听某给端口
- 常用的端口号
- 16位UDP长度.
- 首部的长度 + 数据的长度
- 16位UDP检验和
- 伪首部仅在计算检验和时候起作用, 并不会传递到网络层.
- 16位源端口号
- 固定长度8个字节
-
特性
- 面向无连接
- 减少了建立和释放连接的开销
- 不可靠传输协议
- 不保证可靠交付
- 因为不可靠和无连接, 因此不需要为维护一些复杂的参数
- 面向无连接
-
UDP 是导致 IP分片的主要原因, TCP 不会导致IP分片, 因为TCP 有MSS.同时TCP如果包很小, 就会将多个数据包一起发送, 就会导致粘包.
-
长连接和短连接是应用层控制的, 指的是应用层控制TCP 数据传输完成后立即断开, 还是不断开.
-
TCP的建立连接和断开连接 需要经过三次握手和四次挥手. 和具体的应用层协议无关.
-
五元组确定唯一的Socket, IP.Src, IP.Dst, Port.Src, Port.Dst, protocol. DNS就是TCP和UDP共用53号端口