物理层:底层数据传输,如网线;网卡标准
数据链路层:定义数据的基本格式,如何传输,如何标识,如网卡MAC地址。
网络层:定义IP编址,定义路由功能;如不同设备的数据转发。
传输层:端到端数据的基本功能;如TCP、UDP。
会话层:控制应用程序之间的会话能力;如不同软件数据分发给不同软件。
表示层:数据格式标识,基本压缩加密功能。
应用层:各种应用软件,包括Web应用。
第一次握手:建立连接时,客户端向服务器发送SYN包(seq=x),请求建立连接,等待确认
第二次握手:服务端收到客户端的SYN包,回一个ACK包(ACK=x+1)确认收到,同时发送一个SYN包(seq=y)给客户端
第三次握手:客户端收到SYN+ACK包,再回一个ACK包(ack=y+1),告诉服务端已经收到
三次握手完成,成功建立连接,开始传输数据
握手状态变迁:
CLOSED:阻塞或关闭状态,表示主机当前没有正在传输或者建立的链接
LISTEN:监听状态,表示服务器做好准备,等待建立传输链接
SYN RECV:收到第一次的传输请求,还未进行确认
SYN SENT:发送完第一个SYN报文,等待收到确认
ESTABLISHED:链接正常建立之后进入数据传输阶段
客户端发送FIN包(FIN=1)给服务端,告诉它自己的数据已经发送完毕,请求终止连接,此时客户端不发送数据,但还能接受数据(因为服务端还没断开连接,可能还会发送数据)
服务端收到FIN包,回一个ACK包给客户端告诉它已经收到包了,但还没有断开socked连接,而是等待剩下的数据传输完毕
服务端等待数据传输完毕后,向客户端发送FIN包,表明可以断开连接
客户端收到后,回一个ACK包表明确认收到,等待一段时间,确保服务端不再有数据发过来,然后彻底断开连接(TIME-WAIT)
挥手状态变迁:
FIN_WAIT1:主动发送第一个FIN报文之后进入该状态。
FIN WAIT2:已经收到第一个FIN的确认信号,等待对方发送关闭请求
TIMED WAIT:完成双向链接关闭,等待分组消失
CLOSING:双方同时关闭请求,等待对方确认时
CLOSE WAIT:收到对方的关闭请求并进行确认进入该状态
LAST ACK:等待最后一次确认关闭的报文
TCP是面向连接的,udp是无连接的即发送数据前不需要先建立连接
TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付。 并且因为tcp可靠,面向连接,不会丢失数据因此适合大数据量的交换。
TCP是面向字节流,UDP面向报文,并且网络出现拥塞不会使得发送速率降低(因此会出现丢包,对实时的应用比如IP电话和视频会议等)。
TCP只能是1对1的,UDP支持1对1,1对多。
TCP的首部较大为20字节,而UDP只有8字节。
TCP是面向连接的可靠性传输,而UDP是不可靠的。
弄清这个问题,我们需要先弄明白三次握手的目的是什么,能不能只用两次握手来达到同样的目的。
第一次握手:客户端发送网络包,服务端收到了。 这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
第二次握手:服务端发包,客户端收到了。 这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。
第三次握手:客户端发包,服务端收到了。 这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。
因此,需要三次握手才能确认双方的接收与发送能力是否正常。
为了实现可靠数据传输,TCP协议的通信双方,都必须维护一个序列号,以标识发送出去的数据包中,哪些是已经被对方收到的。三次握手的过程既是通双方相告知序列号起始值,并确认对方已经收到了序列号起始值的必经步骤。
如果只是两次握手,至多只有连接发起方的起始序号都能被确认,另一方选择的序列号得不到确认。
序号(32bit):传输方向上字节流的字节编号。初始时序号会被设置一个随机的初始值(ISN),之后每次发送数据时,序号值 = ISN + 数据在整个字节流中的偏移。假设A -> B且ISN = 1024,第一段数据512字节已经到B,则第二段数据发送时序号为1024 + 512。用于解决网络包乱序问题。
确认号(32bit):接收方对发送方TCP报文段的响应,其值是收到的序号值 + 1。
首部长(4bit):标识首部有多少个4字节 * 首部长,最大为15,即60字节。
标志位(6bit):
URG:标志紧急指针是否有效。
ACK:标志确认号是否有效(确认报文段)。用于解决丢包问题。
PSH:提示接收端立即从缓冲读走数据。
RST:表示要求对方重新建立连接(复位报文段)。
SYN:表示请求建立一个连接(连接报文段)。
FIN:表示关闭连接(断开报文段)。
窗口(16bit):接收窗口。用于告知对方(发送方)本方的缓冲还能接收多少字节数据。用于解决流控。
校验和(16bit):接收端用CRC检验整个报文段有无损坏
HTTP 超文本传输协议
HTTPS 超文本传输安全协议
FTP 文件传输协议
Telnet 远程登陆服务的标准协议
DNS 域名解析服务(服务器进行域传输的时候用TCP,客户端查询DNS服务器的时候用UDP)
SMTP 简单邮件传输协议(发送用)
POP 邮局协议(接收用)
第三次发送的时候是可以携带是数据得,第一次第二次不能携带。
第一次握手不可以放数据,其中一个简单得原因是会让服务器更加容易收到攻击。(假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据。因为攻击者根本就不理服务器的接收、发送能力是否正常,然后疯狂着重复发 SYN 报文的话,这会让服务器花费很多时间、内存空间来接收这些报文。)
对于第三次,此时客户端已经处于ESTABLISHED状态,对于客户端来说,他已经建立起连接了,并且也已经知道服务器的接受、发送能力是正常的,故可携带数据。
此问题摘自大佬的博客
在三次握手过程中,服务器发送 SYN-ACK 之后,收到客户端的 ACK 之前的 TCP 连接称为半连接(half-open connect)。此时服务器处于 SYN_RCVD 状态。当收到 ACK 后,服务器才能转入 ESTABLISHED 状态.
SYN 攻击指的是,攻击客户端在短时间内伪造大量不存在的IP地址,向服务器不断地发送SYN包,服务器回复确认包,并等待客户的确认。由于源地址是不存在的,服务器需要不断的重发直至超时,这些伪造的SYN包将长时间占用未连接队列,正常的SYN请求被丢弃,导致目标系统运行缓慢,严重者会引起网络堵塞甚至系统瘫痪。
SYN 攻击是一种典型的 DoS/DDoS 攻击。
如何防御 SYN 攻击?
SYN攻击不能完全被阻止,除非将TCP协议重新设计。我们所做的是尽可能的减轻SYN攻击的危害,常见的防御 SYN 攻击的方法有如下几种:
缩短超时(SYN Timeout)时间
增加最大半连接数
防火墙过滤防护
SYN cookies技术
因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文我收到了”。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。
为了保证客户端发送的最后一个ACK报文段能够到达服务器。因为这个ACK有可能丢失,从而导致处在LAST-ACK状态的服务器收不到对FIN-ACK的确认报文。服务器会超时重传这个FIN-ACK,接着客户端再重传一次确认,重新启动时间等待器。最后客户端和服务器都能正常关闭。假设客户端不等待2MSL,而是在发送完ACK后直接释放关闭,一旦这个ACK丢失的话,服务器就无法正常的进入关闭连接状态。
所谓慢启动,也就是TCP连接刚建立,一点一点地提速,试探一下网络的承受能力,以免直接扰乱了网络通道的秩序。
慢启动算法:
拥塞避免算法 – Congestion Avoidance
如同前边说的,当拥塞窗口大小cwnd大于等于慢启动阈值ssthresh后,就进入拥塞避免算法。算法如下:
过了慢启动阈值后,拥塞避免算法可以避免窗口增长过快导致窗口拥塞,而是缓慢的增加调整到网络的最佳值
一般来说,TCP拥塞控制默认认为网络丢包是由于网络拥塞导致的,所以一般的TCP拥塞控制算法以丢包为网络进入拥塞状态的信号。对于丢包有两种判定方式,
超时重传是TCP协议保证数据可靠性的一个重要机制,其原理是在发送一个数据以后就开启一个计时器,在一定时间内如果没有得到发送数据报的ACK报文,那么就重新发送数据,直到发送成功为止。
但是如果发送端接收到3个以上的重复ACK,TCP就意识到数据发生丢失,需要重传。这个机制不需要等到重传定时器超时,所以叫做快速重传,而快速重传后没有使用慢启动算法,而是拥塞避免算法,所以这又叫做快速恢复算法。
超时重传RTO[Retransmission Timeout]超时,TCP会重传数据包。TCP认为这种情况比较糟糕,反应也比较强烈:
最为早期的TCP Tahoe算法就只使用上述处理办法,但是由于一丢包就一切重来,导致cwnd又重置为1,十分不利于网络数据的稳定传递。
所以,TCP Reno算法进行了优化。当收到三个重复确认ACK时,TCP开启快速重传Fast Retransmit算法,而不用等到RTO超时再进行重传:
当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把慢开始门限减半。这是为了预防网络发生拥塞,但不执行慢开始算法。
由于发送方现在认为网络很可能没有发生拥塞(如果网络发生了严重拥塞,就不会一连有好几个报文段连续到达接收方,也就不会导致接收方连续发送重复确认)。因此与慢开始不同之处就是现在不执行慢开始算法(即拥塞窗口现在不设置为1)而是把拥塞窗口的值设置为慢开始门限减半后的值,然后开始执行拥塞避免算法(“加法增大”),使拥塞窗口缓慢地线性增大。
目的是接收方通过TCP头窗口字段告知发送方本方可接收的最大数据量,用以解决发送速率过快导致接收方不能接收的问题。所以流量控制是点对点控制。
TCP是全双工协议,双方可以同时通信,所以发送方接收方各自维护一个发送窗和接收窗。
发送窗:用来限制发送方可以发送的数据大小,其中发送窗口的大小由接收端返回的TCP报文段中窗口字段来控制,接收方通过此字段告知发送方自己的缓冲(受系统、硬件等限制)大小。
接收窗:用来标记可以接收的数据大小。
TCP是流数据,发送出去的数据流可以被分为以下四部分:已发送且被确认部分 | 已发送未被确认部分 | 未发送但可发送部分 | 不可发送部分,其中发送窗 = 已发送未确认部分 + 未发但可发送部分。接收到的数据流可分为:已接收 | 未接收但准备接收 | 未接收不准备接收。接收窗 = 未接收但准备接收部分。
发送窗内数据只有当接收到接收端某段发送数据的ACK响应时才移动发送窗,左边缘紧贴刚被确认的数据。接收窗也只有接收到数据且最左侧连续时才移动接收窗口
流量控制是为了控制发送方发送速率,保证接收方来得及接收。TCP利用滑动窗口实现流量控制。
TCP中采用滑动窗口来进行传输控制,滑动窗口的大小意味着接收方还有多大的缓冲区可以用作接受数据。发送方可以通过滑动窗口的大小来确定应该发送多少字节的数据。当滑动窗口为0时,发送方一般不能再发送数据报。
确认和重传:接收方收到报文就会确认,发送方发送一段时间后没有收到确认就会重传。
数据校验:TCP报文头有校验和,用于校验报文是否损坏。
数据合理分片和排序:tcp会按最大传输单元(MTU)合理分片,接收方会缓存未按序到达的数据,重新排序后交给应用层。而UDP:IP数据报大于1500字节,大于MTU。这个时候发送方的IP层就需要分片,把数据报分成若干片,是的每一片都小于MTU。而接收方IP层则需要进行数据报的重组。由于UDP的特性,某一片数据丢失时,接收方便无法重组数据报,导致丢弃整个UDP数据报。
流量控制:当接收方来不及处理发送方的数据,能通过滑动窗口,提示发送方降低发送的速率,防止包丢失。
拥塞控制:当网络拥塞时,通过拥塞窗口,减少数据的发送,防止包丢失
封包和拆包都是基于TCP的概念。因为TCP是无边界的流传输,所以需要对TCP进行封包和拆包,确保发送和接收的数据不粘连。
封包:封包就是在发送数据报的时候为每个TCP数据包加上一个包头,将数据报分为包头和包体两个部分。包头是一个固定长度的结构体,里面包含该数据包的总长度。
拆包:接收方在接收到报文后提取包头中的长度信息进行截取。
TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。
产生原因:
解决:
**超时重传:**发送端发送报文后若长时间未收到确认的报文则需要重发该报文。可能有以下几种情况:
RTO:从上一次发送数据,因为长期没有收到ACK响应,到下一次重发之间的时间。就是重传间隔。
RTT:数据从发送到接收到对方响应之间的时间间隔,即数据报在网络中一个往返用时。大小不稳定。
流量控制需要通信双方各维护一个发送窗、一个接收窗,对任意一方,接收窗的大小由自身决定,发送窗大小由接收方响应的TCP报文段中窗口值决定;
拥塞控制的拥塞窗口大小变化由试探性发送一定数据量数据探查网络情况后而自适应调整。
65536.因为TCP的报文头部中源端口号和目的端口号的长度是16位,也就是可以表示2^16=65536个不同端口号,因此TCP可供识别的端口号最多只有65536个。但是由于0到1023是知名服务端口,所以实际上还要少1024个端口号。
而对于服务器来说,可以开的端口号与65536无关,其实是受限于Linux可以打开的文件数量,并且可以通过MaxUserPort来进行配置。