什么是 TCP ?
Transmission Control Protocol(传输控制协议)
TCP 是面向连接的、可靠的、基于字节流的传输层通信协议。
面向连接:一定是「一对一」才能连接,不能像 UDP 协议 可以一个主机同时向多个主机发送消息,也就是一对多是无法做到的;
可靠的:无论的网络链路中出现了怎样的链路变化,TCP 都可以保证一个报文一定能够到达接收端;
字节流:消息是「没有边界」的,所以无论我们消息有多大都可以进行传输。并且消息是「有序的」,当「前一个」消息没有收到的时候,即使它先收到了后面的字节已经收到,那么也不能扔给应用层去处理,同时对「重复」的报文会自动丢弃。
什么是 TCP 连接?
TCP连接主要包括三个部分:socket,序列号,窗口大小。
通过TCP连接可以控制流量,和提高可靠性。
- Socket:由 IP 地址和端口号组成
- 序列号:用来解决乱序问题等
- 窗口大小:用来做流量控制
如何唯一确定一个 TCP 连接呢?
- 源地址
- 源端口
- 目的地址
- 目的端口
有一个 IP 的服务器监听了一个端口,它的 TCP 的最大连接数是多少?
主要受限于服务器的资源,第一是文件描述符限制,TCP连接中得socket是文件得,所以受文件描述符限制,这个由系统参数ulimit 配置,但这个也受限于系统内存,内存不大,参数设置得过大也无法实现。
UDP 和 TCP 有什么区别呢?分别的应用场景是?
UDP 是不需要连接,即刻传输数据。且可以一对多,多对多。UDP 是尽最大努力交付,不保证可靠交付数据。UDP没有流量控制。UDP首部只有 8 个字节,并且是固定不变的,开销较小
TCP则是面向连接的,只能一对一,TCP比较可靠数据可以无差错、不丢失、不重复、按需到达,可以进行流量控制。
一句话来说UDP比较高效,舍弃了可靠性,TCP则是专注于点对点的高质量传输。
TCP:
FTP 文件传输
HTTP / HTTPS
UDP
由于 UDP 面向无连接,它可以随时发送数据,再加上UDP本身的处理既简单又高效,因此经常用于:
包总量较少的通信,如 DNS 、SNMP 等
视频、音频等多媒体通信
广播通信
为什么 UDP 头部没有「首部长度」字段,而 TCP 头部有「首部长度」字段呢?
原因是 TCP 有可变长的「选项」字段,而 UDP 头部长度则是不会变化的,无需多一个字段去记录 UDP 的首部长度。
三次握手,四次挥手
三次握手
- 一开始,客户端和服务端都处于 CLOSED 状态。先是服务端主动监听某个端口,处于 LISTEN 状态;
- 客户端发起一个SYN请求,同时送过去随机生成的客户端序列号client_isn,之后客户端处于 SYN-SENT 状态。
- 服务端接收到SYN请求,返回一个ACK和服务端的SYN,其次把 TCP 首部的「确认应答号」字段填入 client_isn + 1,生成一个服务端的序列号server_isn,传送给客户端,之后服务端处于 SYN-RCVD 状态;
- 客户端收到服务端报文后,还要向服务端回应最后一个应答报文,首先该应答报文 TCP 首部 ACK 标志位置为 1 ,其次「确认应答号」字段填入 server_isn + 1 ,最后把报文发送给服务端,这次报文可以携带客户到服务器的数据,之后客户端处于 ESTABLISHED 状态。
- 服务器收到客户端的应答报文后,也进入 ESTABLISHED 状态。
三次握手的意义
阻止历史重复连接的初始化(主要原因)
三次握手才可以同步双方的初始序列号
三次握手才可以避免资源浪费
从上面的过程可以发现第三次握手是可以携带数据的,前两次握手是不可以携带数据的。
如何在 Linux 系统中查看 TCP 状态?
TCP 的连接状态查看,在 Linux 可以通过 netstat -napt 命令查看。
四次挥手
- 客户端打算关闭连接,此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文,也即 FIN 报文,之后客户端进入 FIN_WAIT_1 状态。
- 服务端收到该报文后,就向客户端发送 ACK 应答报文,接着服务端进入 CLOSED_WAIT 状态。
- 客户端收到服务端的 ACK 应答报文后,之后进入 FIN_WAIT_2 状态。
- 等待服务端处理完数据后,也向客户端发送 FIN 报文,之后服务端进入 LAST_ACK 状态。
- 客户端收到服务端的 FIN 报文后,回一个 ACK 应答报文,之后进入 TIME_WAIT 状态
- 服务器收到了 ACK 应答报文后,就进入了 CLOSE 状态,至此服务端已经完成连接的关闭。
- 客户端在经过 2MSL 一段时间后,自动进入 CLOSE 状态,至此客户端也完成连接的关闭。
主动关闭连接的,才有 TIME_WAIT 状态。
TCP性能的优化
tcp_syn_retries 控制SYN包重传的次数,默认值是5
1 | echo 5 > /proc/sys/net/ipv4/tcp_syn_retries |
如何查看由于 SYN 半连接队列已满,而被丢弃连接的情况?
1 | netstat -s |grep "SYNs to LISTEN" |
上面输出的数值是累计值,表示共有多少个 TCP
连接因为半连接队列溢出而被丢弃。隔几秒执行几次,如果有上升的趋势,说明当前存在半连接队列溢出的现象。
如何查看由于 accept 连接队列已满,而被丢弃的连接?
1 | date;netstat -s |grep overflowed |