计算机为了联网,就必须规定通信协议
为了将所有类型的计算机都连接起来,规定了全球通用协议。互联网协议簇(Internet Protocol Suite)
互联网上每个计算机有唯一标识的IP地址,IP地址对应的实际上是计算机的网络接口,通常是网卡。
一、IP协议
IP协议负责把数据从一台计算机通过网络发送到另一台计算机。数据被分割成一小块一小块,然后通过IP包发送出去。由于互联网链路复杂,两台计算机之间经常有多条线路,因此,路由器就负责决定如何把一个IP包转发出去。IP包的特点是按块发送,途径多个路由,但不保证能到达,也不保证顺序到达。
二、TCP协议
TCP协议负责在两台计算机之间建立可靠连接,保证数据包按顺序到达。TCP协议会通过握手建立连接,然后,对每个IP包编号,确保对方按顺序收到,如果包丢掉了,就自动重发。
许多常用的更高级的协议都是建立在TCP协议基础上的,比如用于浏览器的HTTP协议、发送邮件的SMTP协议等。
一个TCP报文除了包含要传输的数据外,还包含源IP地址和目标IP地址,源端口和目标端口。
端口有什么作用?在两台计算机通信时,只发IP地址是不够的,因为同一台计算机上跑着多个网络程序。一个TCP报文来了之后,到底是交给浏览器还是QQ,就需要端口号来区分。每个网络程序都向操作系统申请唯一的端口号,这样,两个进程在两台计算机之间建立网络连接就需要各自的IP地址和各自的端口号。
一个进程也可能同时与多个计算机建立链接,因此它会申请很多端口。
如何创建TCP连接,创建连接的时,主动发起连接的是客户端,被动响应连接的叫服务器
由于TCP不存在连接的概念,只存在请求和响应,请求和响应都是数据包,它们之间都是经过由TCP创建的一个从客户端发起,服务器接收的类似连接的通道,这个连接可以一直保持,http请求是在这个连接的基础上发送的;
“三次握手协议”:
“第三次握手”是客户端向服务器端发送数据,这个数据就是要告诉服务器,客户端有没有收到服务器“第二次握手”时传过去的数据。若发送的这个数据是“收到了”的信息,接收后服务器就正常建立TCP连接,否则建立TCP连接失败,服务器关闭连接端口。由此减少服务器开销和接收到失效请求发生的错误。
那么为什么需要第三次握手呢?我们来看一下,假设一下如果没有第三次握手,而是两次握手后我们就认为连接成功了,那么会发生什么?第三次握手是为了防止已经失效的连接请求报文段突然又传到服务端,因而产生错误。
譬如发起请求遇到类似这样的情况:客户端发出去的第一个连接请求由于某些原因在网络节点中滞留了导致延迟,直到连接释放的某个时间点才到达服务端,这是一个早已失效的报文,但是此时服务端仍然认为这是客户端的建立连接请求第一次握手,于是服务端回应了客户端,第二次握手。
在这里主要介绍一下那6个标志位
URG:紧急指针标志,当为1时表示紧急指针有效,为0则忽略紧急指针
ACK:确认序号标志,为1表示确认号有效,为0表示报文中不含有确认信息,确认号无效
PSH:push标志,当为1时就是让接收方收到该TCP报文的时候不进入缓冲区排队而是快速发给应用程序
RST:重置连接标志,当连接出现错误时可以重置,或者用于拒绝非法的报文段和连接请求
SYN:同步序号,用于建立连接过程
FIN:finish标志,用于释放连接
(注:seq代表序号,ack代表确认号)
第一次握手:当客户端需要去建立连接时,客户端就会发送SYN包(seq=x)到服务器,然后客户端进入SYN_SEND的状态,代表已经发SYN包过去,并且在等待服务器确认。此时ACK=0,SYN=1.,这时候由于才第一次握手,所以没有ACK标志
第二次握手:服务器收到SYN包,就会进行确认,由上面的标志位介绍我们可以知道SYN是表示同步序号,这时候会使得确认号=序号+1,即ack就会等于x+1,然后服务器也会像客户端发送一个SYN包(seq=y),这时候也就是服务器会发送SYN+ACK包,来表示服务器确认到了客户端的一次握手并且二次握手建立,此时服务器进入SYN_RECV状态。此时SYN=1,ACK=1,这时候由于是第二次握手,所以就会有一个服务器给客户端的确认标志。
第三次握手:客户端收到服务器的SYN+ACK包,然后就会像服务器发送确认包ACK(ack=k+1)和SYN(seq=x+1),等到这个包发送完毕之后客户端和服务器就会进入ESTABLISHED状态,完成三次握手,而后就可以在服务端和客户端之间传输数据。此时SYN标志位已经不需要,因为当我们发送ACK标志位的时候代表三次握手成功,已经建立完连接了,接下来可以传送数据过去了。
既然都有SYN包那为什么还要ACK来确认呢?SYN是同步序号,当 SYN=1 而ACK=0 时,表明这是一个连接请求报文。对方若同意建立连接,则应在响应报文中使 SYN=1 和 ACK=1。因此SYN置1就表示这是一个连接请求或连接接受报文。而ACK状态是用来确认是否同意连接。也就是传了 SYN,证明发送方到接收方的通道没有问题,但是接收方到发送方的通道还需要 ACK 信号来进行验证。
当TCP三次握手完之后,就代表连接已经建立完成,那么连接断开又是怎么样的呢?
"四次挥手协议":
当在传送完数据之后,客户端会和服务端之间有四次握手
第一次握手:客户端发送一个FIN和序号过去(seq=u),用来表示客户端和服务端之间有关闭的请求,同时关闭客户端到服务端的数据传送,客户端就进入FIN_WAIT_1的状态。
第二次握手:服务端收到FIN=1的标志位时,就会发送一个ACK标志位代表确认,然后确认序号就变成了收到的序号加1,即ack=u+1(FIN和SYN在这点上相同,但是作用不一样)这时候服务端进入CLOSE_WAIT状态,这是一个半关闭状态。只能服务端给客户端发送数据而客户端不能给服务端发送数据。
第三次握手:这次握手还是由服务端发起,这是服务端在传完最后的数据(没有就不传)就会发送一个FIN=1和ACK=1,且序号seq会改变(没有传数据则不变),而ack不变。这时候服务端就会进入LAST_ACK状态,表示最后确认一次。
第四次握手:客户端在接收到FIN之后,就会进入TIME_WAIT状态,接着就发送一个ACK和seq=u+1,ack=w+1给服务端,这时候服务端就会进入CLOSED状态。而客户端进入TIME_WAIT状态的时候必须要等待2MSL的时间才会关闭
为什么会有TIME_WAIT状态呢?(MSL:网络中数据报文存在的最大时间)
1、TIME_WAIT状态可以确保有足够的时间让对方接收到ACK包,如果ACK没有到达,在传输的过程丢失了或者一些其他原因,这样就可以让客户端重发ACK包。如果客户端直接关闭了,那么就有可能导致服务端在一些情况下没有接收到ACK包而无法与客户端断开连接。这样客户端发送ACK包到服务端,服务端请求重发,一来一回就正好是2MSL
2、保证迟来的TCP报文段有足够的时间被识别并丢弃,linux 中一个TCPport不能打开两次或两次以上。当client处于time_wait状态时我们将无法使用此port建立新连接,假设不存在time_wait状态,新连接可能会收到旧连接的数据。
服务器出现大量COLSE_WAIT状态的原因?这时候很可能是因为程序中在收到FIN=1的TCP报文后,由于忙于读或者写,没有去及时发送FIN回来,也就是无法及时关闭连接。这时候需要着重检查释放资源的代码和处理请求的线程配置,有可能是代码中有资源没有被释放掉,也有可能是线程池中的线程数不合理等等