之前学习了很多关于网络层的协议,例如IP协议、arp协议、icmp协议等,接下来我们要学习TCP/IP五层协议中的第三层-传输层中的两个协议:TCP协议和UDP协议,以及TCP协议中非常重要的三次握手、四次挥手。
文章目录
- 传输层协议
- TCP和UDP
- TCP的封装格式
- TCP其他问题
- 三次握手
- 四次挥手
- 三次握手与四次挥手的整体流程图
- 三次握手四次挥手中的常见问题
- UDP
传输层协议
传输层的协议包括TCP和UDP
传输层选择哪个协议,取决于应用层的特点和业务的特点
传输层的作用:IP层提供点到点的连接,传输层提供端到端的连接
不同的应用程序监听着不同的端口,通过不同的端口号来区别,应用层和传输层通过端口号来连接
socket 套接字: ip+port 192.168.0.1:80 -->一个程序占用一个ip地址的一个端口号
访问这个套接字就是访问一个程序
传输层中比较经典的端口号:
http 80 -TCP
mysql 3306 -TCP
ssh 22 -TCP (密文传输)
ftp 21 -TCP
telnet 23 -TCP (远程控制的,明文传输,不安全)
SMTP 25 -TCP (发送邮件)
pop3 110 -TCP (收取邮件)
dns 53 -TCP (dns的主从服务器之间的数据传输)
dns 53 -UDP (域名解析过程中是UDP)
QQ 8000 -UDP
dhcp 67 -UDP
ntp(网络时间协议) 123 -UDP
TCP和UDP
TCP(Transmission Control Protocol):面向连接,可靠,手续多,但是速度慢(可以比喻成打电话)
特点:
- 传输控制协议
- 可靠的、面向连接的协议 (三次握手,四次挥手体现了面向连接的特点;计时器,重传计时器体现了可靠的特点)
- 传输效率低 (面向连接,总是需要确认,体现了传输效率低的特点)
UDP(User Datagram Protocol):无连接,不可靠,手续少,而且速度快(比喻成发短信)
QQ、dhcp就是使用UDP的,QQ服务器的端口号是8000
特点:
- 用户数据报协议
- 不可靠的、无连接的服务
- 传输效率高
TCP的封装格式
TCP的封装格式:封装头部占20个字节(IP头部也是20个字节,帧头部是18个字节)
- 端口号的范围:0~65535,也就是2^16 【0-1024】是经典端口号,不要使用
- 序列号(seq序号):数据段标记,用于到目的端对到达包的重组
- 确认号(ack序号):对发送端的确认信息,告诉发送端这个序列号之前的数据段都收到了(如果A给B发送的确认号是1000,B给A回复的是999,那就证明这个1000 B没有收到,如果B回复的是1001,那就证明1000收到了)只有ACK标志位为1时,确认序列号才有效,ack=上一个的seq+1
谢希仁老师书中对序列号和确认号的解析:
- 6个标志位(要么为0,要么为1):
URG (urgent):紧急指针有效位,与16位紧急指针配合使用
ACK(acknowledgement):确认序列号有效位,表明该数据包包含确认信息,三次连接之后,ACK位一直置为1
PSH(push):通知接收端立即将数据提交给用户进程,不在缓存中停留,等待更多的数据
RST(reset):请求重新建立TCP连接—重置
SYN(sync):请求建立连接—同步
FIN(finish):数据发送完毕,请求断开连接 - 窗口大小:滑动窗口的大小,指明本地可接收数据的字节数(通过指定滑动窗口的大小,来进行流量控制)
TCP其他问题
crowd window拥塞窗口
中间链路带宽比较窄,传输时窗口大小根据拥塞窗口(记为cwnd)的大小变化,拥塞窗口决定滑动窗口的大小
拥塞控制的四大算法(解决拥塞的办法,四个阶段):
1)慢启动;
2)拥塞避免;
3)拥塞发生(快重传);
4)快速恢复
TCP差错控制的3种方式:
- 校验和 校验封装头部是否被更改
- 确认
-
- 受损伤的数据段
-
- 丢失的数据段
-
- 重复的数据段
-
- 失序的数据段
-
- 确认的丢失
- 超时 —计时器
-
- 重传计时器 — 为了控制丢失的数据段,最多重传三次
-
- 坚持计时器 — 为了防止零窗口死锁
-
- 保活计时器 — 防止两个TCP之间的连接长时间的空闲
-
- 时间等待计时器 — 连接终止时期使用的,在发送了最后一个ACK之后,不立即关闭连接,而是等待一段时间,保证能接收到重复的FIN数据段,2MSL
三次握手
服务器和客户端通过三次握手建立连接,那么三次握手的具体过程又是怎样的呢?
对于三次握手,我的理解是这样的:
首先,我们假设有一台客户端A和一台服务器B,现在A想访问B,那么首先就需要跟B建立连接。
- 刚开始的时候,客户端是处于一个closed的状态,服务器端由closed的状态被动的变为listen状态。
- 第一次握手:客户端给服务器端发送一个SYN报文(也就是TCP封装格式中的标志位的SYN置为1),并且指明客户端的初始序列号seq为x。此时,客户端处于SYN_SENT状态。
- 第二次握手:服务器端收到客户端的SYN报文后,也会给客户端发送一个SYN报文,表示同意建立连接,并且序列号确认有效位也为1。然后还指定了自己的初始序列号seq为y,确认号ACK为x+1,表明收到了客户端的SYN报文。此时,服务端处于SYN_RCVD状态。
- 第三次握手:客户端收到服务端的SYN报文后,会发送一个ACK报文,也会把服务端的初始序列号y+1作为自己的确认号ACK的值,表示收到了服务端的SYN报文。此时,客户端处于established状态
- 服务端收到ACK报文后,也处于established状态。自此,双方就都建立了连接,可以传送数据了。
四次挥手
当服务端和客户端的数据传送完成之后,便要断开连接,这个连接可以是客户端主动叉掉页面断开的,也可以超过连接时间了,服务端主动断开的,接下来我以客户端主动断开为例来说明这个过程:
刚开始的时候,双方都处于established状态。
- 第一次挥手:客户端发送了FIN报文给服务端,报文中指定了初始序列号为u。此时,客户端处于FIN_WAIT1的状态。
- 第二次挥手:服务端收到客户端的FIN报文后,会给客户端发送一个ACK报文,表明收到了对方的FIN报文。这个报文中,会把客户端的序列号u+1作为自己ACK报文确认号的值,也会生成一个初始序列号v。此时,服务端处于CLOSE_WAIT的状态。
- 第三次挥手:如果服务器此时也想要断开,跟客户端的第一次挥手一样,会再给客户端发送一个FIN报文,随机指定一个序列号seq为w。此时,服务端处于LAST_ACK的状态。
- 第四次挥手:客户端收到服务端的FIN报文后,一样的会发送一个ACK报文作为应答,并且会把服务端的序列号w+1作为自己ACK报文确认号的值。此时,客户端处于TIME_WAIT状态,需要过一阵子以确保服务端收到自己的ACK报文后才会进入CLOSED状态,一般会等待2MSL。
- 服务端收到ACK报文后,就处于关闭连接了,处于CLOSED状态。自此,四次挥手的过程也结束了。
三次握手与四次挥手的整体流程图
三次握手四次挥手中的常见问题
【问题1】为什么要三次握手?
三次握手的目的是建立可靠的通信信道,说到通讯,简单来说就是数据的发送与接收,而三次握手最主要的目的就是双方确认自己与对方的发送与接收是正常的
第一次握手,发送端:什么都确认不了;接收端:对方发送正常,自己接受正常
第二次握手,发送端:对方发送,接受正常,自己发送,接受正常 ;接收端:对方发送正常,自己接受正常
第三次握手,发送端:对方发送,接受正常,自己发送,接受正常;接收端:对方发送,接受正常,自己发送,接受正常
【问题2】为什么连接的时候是三次握手,关闭的时候却是四次挥手?
答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
【问题3】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。timewait理论上最长等待4分钟。
【问题4】为什么不能用两次握手进行连接?
答:3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
现在把三次握手改成仅需要两次握手,死锁是可能发生的。作为例子,考虑计算机S和C之间的通信,假定C给S发送一个连接请求分组,S收到了这个分组,并发 送了确认应答分组。按照两次握手的协定,S认为连接已经成功地建立了,可以开始发送数据分组。可是,C在S的应答分组在传输中被丢失的情况下,将不知道S 是否已准备好,不知道S建立什么样的序列号,C甚至怀疑S是否收到自己的连接请求分组。在这种情况下,C认为连接还未建立成功,将忽略S发来的任何数据分 组,只等待连接确认应答分组。而S在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。
【问题5】如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
【问题6】服务器timewait比较多是什么原因?
timewait出现在四次挥手中的主动断开连接方,timewait比较多就说明要断开的服务很多,一方面可以说明服务器的访问量很多,如果访问量小,是不可能有那么多timewait的。另外一方面,就是用户访问你的服务之后,很长时间没有发送新的请求,也就是用户没有再看你的网站了。
【问题7】服务器timewait比较多,会造成一定的时间和资源浪费,如何高效的利用timewait的等待时间呢?
编辑内核文件/etc/sysctl.conf,加入以下内容:
net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_fin_timeout 修改系默认的 TIMEOUT 时间
然后执行 /sbin/sysctl -p 让参数生效.
/etc/sysctl.conf是一个允许改变正在运行中的Linux系统的接口,它包含一些TCP/IP堆栈和虚拟内存系统的高级选项,修改内核参数永久生效,可以进行内核参数调优。
简单来说,就是打开系统的TIMEWAIT重用和快速回收。
【问题8】服务器的lastack比较多说明什么问题?
LAST_ACK出现在四次挥手中被动断开方,说明有很多主机访问你,然后又断开,有可能是有人故意攻击你的服务器,造成资源浪费。
【问题9】什么是SYN洪范泛攻击?
SYN Flood利用TCP协议缺陷,发送大量伪造的TCP连接请求,常用假冒的IP或IP号段发来海量的请求连接的第一个握手包(SYN包),被攻击服务器回应第二个握手包(SYN+ACK包),因为对方是假冒IP,对方永远收不到包且不会回应第三个握手包。导致被攻击服务器保持大量SYN_RECV状态的“半连接”,并且会重试默认5次回应第二个握手包,大量随机的恶意syn占满了未完成连接队列,导致正常合法的syn排不上队列,让正常的业务请求连接不进来。【服务器端的资源分配是在二次握手时分配的,而客户端的资源是在完成三次握手时分配的,所以服务器容易受到SYN洪泛攻击】
检测 SYN 攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击【在 Linux/Unix 上可以使用系统自带的 netstats 命令来检测 SYN 攻击】
【问题10】如何解决SYN洪范攻击?
缩短超时(SYN Timeout)时间
增加最大半连接数
过滤网关防护
SYN cookies技术:
当服务器接受到 SYN 报文段时,不直接为该 TCP 分配资源,而只是打开一个半开的套接字。接着会使用 SYN 报文段的源 Id,目的 Id,端口号以及只有服务器自己知道的一个秘密函数生成一个 cookie,并把 cookie 作为序列号响应给客户端。
如果客户端是正常建立连接,将会返回一个确认字段为 cookie + 1 的报文段。接下来服务器会根据确认报文的源 Id,目的 Id,端口号以及秘密函数计算出一个结果,如果结果的值 + 1 等于确认字段的值,则证明是刚刚请求连接的客户端,这时候才为该 TCP 分配资源
更多关于三次握手四次挥手的面试题目:三次握手、四次挥手面试常考题
UDP
UDP的流控和差错控制:
UDP没有流控机制
UDP只有校验和来提供差错控制,需要上层协议来提供差错控制:例如TFTP协议
tcp如何保证可靠的呢?
1.校验和
2.确认应答与序列号
3.超时重传
4.连接管理 —三次握手、四次挥手
5.流量控制
[文章中部分内容借鉴了其他博客,如果侵权请联系我删除!]