- TCP/IP
- TCP/IP协议族
- HTTP(HyperText Transfer Protocol)(应用层协议)
- HTTPS(HyperText Transfer Protocol Secure) (应用层协议)
- SMTP(Simple Mail Transfer Protocol) (应用层协议)
- POP3(Post Office Protocol 3)
- IMAP(Internet Mail Access Protocol)
- DNS(Domain Name System) (应用层协议)
- FTP(File Transfer Protocol)(应用层协议)
- SFTP(Secure File Transfer Protocol) (应用层协议)
- Telnet / SSH(Secure Shell) (应用层协议)
- TCP协议(Transmission Control Protocol)
- TCP为什么可靠性较高?
- UDP协议(User Datagram Protocol)
- TCP与UDP主要区别
- TCP如何保证可靠性传输?
- 为什么需要三次握手?
- TCP三次握手的过程
- 为什么需要四次挥手?
- TCP四次挥手的过程
- TCP粘包和半包问题
- 解决TCP消息无边界的办法主要有以下几种:
- TCP/IP协议族
TCP / IP 不仅仅是指TCP和IP这两种协议,而是一系列网络协议的总和, 而这些协议中最核心的2个协议就是TCP和IP,所以被称为TCP/IP网络协议族。 TCP/IP协议族是互联网的基础通信架构。
HTTP超文本传输协议。
是用于Web浏览器和Web服务器之间传递数据的协议。 HTTP协议以明文的方式发送内容,不提供任何方式的数据加密, 因此HTTP是一种不太安全的协议。
HTTPS协议在HTTP协议的基础上加入了SSL协议, SSL依靠证书来验证服务器的身份, 所以HTTPS协议叫HTTP协议来说是安全的。 SSL协议作用于传输层协议和各种应用层协议之间。
SMTP简单邮件传输协议。
它是用于从源地址到目标地址传输邮件的协议(发送邮件)
POP邮局协议的第3个版本。
POP3协议允许电子邮件客户端下载服务器上的邮件, 但是在客户端上的操作,并不会反馈到服务器上。 也就是说客户端的操作对服务端没有影响。(接受并处理邮件)
IMAP交互式邮件存取协议。
它和POP3协议类似 ,但是IMAP对客户端的操作会反馈到服务端, 也就是说客户端邮件的状态与服务端邮件的状态是一致的。(接受并处理邮件)
DNS域名系统。
DNS服务器可以看做是一个域名与IP地址相互映射的分布式数据库。 我们使用浏览器访问google的时候需要输入:google.com, 浏览器会帮我们到DNS服务器查询google.com对应的IP地址, 从而能够访问google的服务器。
FTP文件传输协议。
FTP协议用于从一台主机将文件传输到另一台主机上。 但FTP协议在文件传输过程中,并没有为文件提供加密措施, 所以FTP协议是不安全的。
SFTP安全文件传输协议。
SFTP实际可以看做是SSH的一部分。 当使用SFTP登录到目标主机后,可以使用SFTP指定的命令进行数据传输, 并且传输的数据是加密过的。
Telnet和SSH都可以作为远程登录的协议。 但Telnet使用的是明文来传输数据,并且没有提供数据加密措施, 是不安全的协议。 而SSH协议则提供了对数据的压缩和加密,比Telnet要安全的多。 所以现在几乎大部分场景都使用的是SSH作为安全数据传输和远程登录的协议, 并且SSH提供了对SFTP的支持。
TCP传输控制协议。
TCP协议是一种面向连接的,可靠的,基于字节流的传输协议。 TCP协议适用于对数据准确性和可靠性要求较高的应用,如文件传输等。
TCP会采用校验和,确认应答与序列号, 拥塞控制,流量控制,超时重传, 连接管理(三次握手,四次回收)等机制保证传输的可靠性。
TCP报文格式:
UDP用户数据报协议。
与TCP协议不同,UDP协议并不保证数据传输的可靠性, 无论目标主机是否可通信,UDP都会发送数据。
UDP适用于传输效率要求较高,允许一定数据丢失的应用,如语音,视频等。
PS:UDP报文格式
- TCP基于连接,数据传输前需要做好可靠性准备工作(三次握手);而UDP是无连接的,只要有数据就可发送了。
- TCP使用流量控制和拥塞控制等措施使传输更加可靠;而UDP则是不可靠的传输。
- TCP是面向流的数据模式(无边界);而UDP是面向报文的数据模式(有边界)。
- TCP仅支持单播,点对点的数据传输;而UDP不仅支持单播,还支持组播,广播。
- TCP首部开销较大(最大60字节,最小20字节);UDP首部开销较小(8字节)。
- 校验和(16位)
在数据传输过程中,将发送的数据段分成若干个16位的整数。 将这些整数加起来,并且前面的进位不能丢弃,补在后面,最后取反, 得到校验和。
发送方在发送数据之前计算校验和,并将校验和填充到TCP报文中, 而接收方收到数据后,对数据以同样的方式进行计算,求出校验和, 与发送方的进行比对。如果比较失败,接收方将丢弃数据包。
- 确认应答ACK和序列号(32位)
在TCP传输过程中,每次接收方收到数据后,都会对发送方进行应答, 也就是响应ACK报文,这个报文中有对应的确认序列号。
- 超时重传
在TCP传输时,由于确认应答和序号机制,当发送方发送完数据后, 会等待接收方的ACK报文,并解析判断ACK报文(一般来说ACK为seq+1), 如果发送方一直没有等到接收方的ACK报文,那么将重新发送一遍数据。
- 连接管理
连接管理是TCP数据传输前和连接断开时的工作, 包括三次握手与四次挥手的过程。
- 流量控制(滑动窗口)
TCP连接发送端和接收端都有一个缓冲区,如果发送端的发送数据过快, 导致接收端来不及处理数据,缓冲区就被填充满了,那么接下来的数据, 接收方就会丢弃数据,导致丢包等连锁反应产生。
TCP根据接收端的处理能力,来决定发送端的发送速度,这个机制就是流量控制。 TCP的报文中,有一个16位的窗口字段, 窗口大小就是接收端计收数据缓冲区的剩余大小,这个数字越大, 代表接收端缓冲区的剩余空间越大。
接收端在发送ACK确认报文时,会将自己当前的窗口大小填入, 这样发送方就会根据ACK报文里的窗口大小的值改变自己的发送速度。 如果接收方窗口大小的值为0,那么发送方将停止发送数据, 并定期的向接收端发送窗口探测数据,让接收端把窗口大小告诉发送端。
- 拥塞控制(拥塞窗口)
滑动窗口是接收端的使用的窗口大小,用来告诉发送端接收端的缓存大小, 从而可以控制发送端的发送速度。 而发送端发送的速度则是使用发送端的窗口来实现的。
发送端的窗口就是拥塞窗口了,发送端的拥塞窗口不代表缓存, 而是指发送端每次最多可以发送的数据包数。
当TCP连接建立时,拥塞窗口被初始化为1,每次发送数据后, 收到一个ACK,拥塞窗口就增加一个报文段, 发送端取拥塞窗口与滑动窗口的最小值作为发送上限,从而实现拥塞控制。
如果网络比较拥堵,那么一次性发送大量数据将,可能产生大量的丢包, 继而发生一系列的连锁反应,如超时重传等。 拥塞控制就避免了一次性发送过多的数据,而导致的问题。
TCP是面向连接的,三次握手是客户端与服务端进行数据传输前的准备工作。 这样做是为了建立可靠的传输信道,尽可能的保证数据的安全。
三次握手是指建立一个TCP连接时需要客户端和服务端总共需要发送3个数据包确认连接的建立。
TCP三次握手的过程:
1.第一次握手
客户端发送一个数据包发送给服务端。 该数据包的标志位SYN=1,表示客户端请求建立连接, 随机产生的序列号seq=J。 客户端进入SYN_SENT状态,等待服务端确认。
2.第二次握手
服务端收到客户端的数据包后,由标志位SYN=1判断客户端需要建立连接。 于是响应一个确认数据包给客户端。 该确认数据包的标志位SYN和标志位ACK都为1,确认序列号ack=J+1, 随机产生的序列号seq=K。服务端进入SYN_RCVD状态。
3.第三次握手
客户端收到服务端的确认数据包后,检查确认序列号ack是否为J+1, 标志位ACK是否为1。 如果正确则将发送最后一个数据包给服务端。 该数据包的标志位ACK为1,确认序列号ack=K+1。 服务端收到后检查确认序列号ack是否为K+1,标志位ACK是否为1。 如果正确,则客户端和服务端都进入ESTABLISHED状态。
三次握手后,客户端和服务端就可以传输数据了。
四次挥手是客户端与服务端关闭连接时的结尾工作。 TCP是全双工的,即:客户端可以通过这条TCP连接向服务端发送数据(上传), 服务端也可以通过这条TCP连接向客户端发送数据(下载)。 因此,客户端和服务端都需要单独的关闭连接。 客户端关闭连接是关客户端到服务端的通信传输, 而服务端关闭连接是关闭服务端到客户端的通信传输, 所以需要四次挥手来保证2端的关闭。
四次挥手是指断开连接时,客户端与服务端总共需要发送4个数据包确认连接的断开。
客户端或服务端任意一方都可以发送断开连接的请求。
TCP四次挥手的过程:
1.第一次挥手(假设客户端请求断开)
客户端发送一个数据包给服务端,用于关闭Client到Server的数据传输。 数据包的标志位FIN=1,随机产生的序号seq=M,客户端进入FIN_WAIT_1状态。
2.第二次挥手
服务端收到客户端的断开请求后,将发送一个数据包响应给客户端。 该数据包的标志位ACK=1,确认序列号ack=M+1。 客户端收到后进入FIN_WAIT_2状态,服务端进入CLOSE_WAIT状态。
3.第三次挥手
服务端发送一个数据包给客户端,用于关闭服务端到客户端的数据传输。 数据包的标志位FIN=1,随机产生的序列号seq=N。 服务端进入LAST_ACK状态。
4.第四次挥手
客户端收到服务端的断开请求后,就可以关闭连接了。 于是发送最后一个数据包结束与服务端的连接,并进入TIME_WAIT状态。 最后一个数据包的标志位ACK=1,确认序列号ack=N+1。 服务端收到最后一个了数据包后,就关闭了连接,状态就为CLOSED, 如果服务端没有收到ACK,客户端可以重传。客户端等了一会儿, 最终没有收到响应,就代表服务端已经关闭连接了,客户端也就会关闭连接。
上面是客户端或服务端中的一段主动关闭,另一段被动关闭, 实际还可能还会出现同时发起关闭的情况:
在TCP传输数据时,客户端发送数据,实际上是把数据写入到了TCP的缓冲区中, 粘包和半包也就可能在此时产生。
假设客户端给服务端发送两条数据: "ABC"和"DEF", 服务端这边的接受可能会有多种情况: 可能是一次性收到了这两条消息:"ABCDEF", 也有可能分批收到了消息:"ABC","DEF"或"AB","CD","EF"。
服务端一次性收到了所有数据包,这种情况就是粘包。
服务端分批收到数据包,这种情况就是半包。
如果客户端发送的包的大小比TCP的缓冲区要小, 并且TCP的缓冲区可以存放多个包,客户端一次性就可能向服务端发送多个包, 这时服务端从TCP缓冲区中就可能读取多个包,这种现象就叫粘包。
如果客户端发送的包的大小比TCP缓冲区要大, 那么这个数据包就可能被分为多个包,就需要多次发送, 而服务端第一次从缓冲区里获取的数据只是整个数据包的一部分,这时候就产生了半包。
粘包的主要原因是: 发送端发送的数据大小 < Socket缓冲区大小, 服务端一次性就读取了Socket缓冲区数据。
半包的主要原因是: 发送端发送的数据大小 > Socket缓冲区大小, 服务端读取数据不够及时,只读取到了数据的一部分。
总结起来就是:多次发送可能共用一个传输,一个发送可能多占用多个传输。
其实归根到底,究其根本原因是:
TCP是面向字节流的协议,消息之间没有边界。 而UDP虽然也可以一次性传输多个包或者多次传输一个包 但UDP的每个消息都是有边界的,因此不会有粘包和半包问题。
-
固定长度:这种方式是为消息设定一个固定长度。虽然实现简单,但缺点很大,如果消息的大小本身就比较小, 那么这样做就很浪费空间了。
-
分隔符:这种方式是为消息边界添加分隔符。这样做实现也是比较简单,也不再浪费空间, 不过当内容本身也有分割符时,那就需要转义了,就可能需要对整个内容进行扫描,效率上就比较低。
-
添加数据的长度字段:这种方式是为报文添加一个Length字段,存储消息的长度。 在Http协议的报文中,有一个字段为Content-Length,专门存储数据的长度,这种方式是比较好的。