1、TCP与UDP概述
TCP (Transmission Control Protocol)和UDP(User Datagram Protocol)协议属于传输层协议。TCP中文全名:传输控制协议,UDP中文全名:用户数据报协议。
其中TCP提供IP环境下的数据可靠传输,提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。通俗说,它是事先为所发送的数据开辟出连接好的通道,然后再进行数据发送;
而UDP是一个简单的面向数据报的运输层协议,即面向非连接。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。TCP支持的应用协议主要有:Telnet、FTP、SMTP等;UDP支持的应用层协议主要有:NFS(网络文件系统)、SNMP(简单网络管理协议)、DNS(主域名称系统)、TFTP(通用文件传输协议)等。
在即时通讯中,QQ采用UDP结合TCP、ICQ采用TCP、JABBER基于TCP
备注:什么是面向连接和面向非连接
“面向连接”就是在正式通信前必须要与对方建立起连接。比如你给别人打电话,必须等线路接通了、对方拿起话筒才能相互通话。
“面向非连接”就是在正式通信前不必与对方先建立连接,不管对方状态就直接发送。与手机短信非常相似:你在发短信的时候,只需要输入对方手机号就OK了。
2、TCP与UDP的区别
(1)连接方式
TCP:需要建立连接,形成传输数据的通道
UDP:不需要建立连接,将数据源和目的封装成数据包中
(2)数据传输的大小
TCP:数据大小不收限制,在连接中进行大数据传输
UDP:每个数据报的大小限制在64K之内
(3)安全性
TCP:通过三次握手完成连接,因此是可靠协议,安全送达
UDP:因为无需连接,因此是不可靠协议
(4)效率性
TCP:必须需要建立连接,所以效率稍微会低些
UDP:不需要建立连接,速度快
3、TCP的三次握手与四次挥手
连接三次握手:
TCP是面向连接的,无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接。在TCP/IP协议中,TCP协议提供可靠的连接服务,连接是通过三次握手进行初始化的。三次握手的目的是同步连接双方的序列号和确认号并交换 TCP窗口大小信息。这就是面试中经常会被问到的TCP三次握手。只是了解TCP三次握手的概念,对你获得一份工作是没有任何帮助的,你需要去了解TCP三次握手中的一些细节。先来看图说话。
多么清晰的一张图,当然了,也不是我做的,是我从网上找来的。
(1)第一次握手:建立连接。客户端发送连接请求报文段,将SYN
位置为1,Sequence Number
为x;然后,客户端进入SYN_SEND
状态,等待服务器的确认;
(2)第二次握手:服务器收到SYN
报文段。服务器收到客户端的SYN
报文段,需要对这个SYN
报文段进行确认,设置Acknowledgment Number
为x+1(Sequence Number
+1);同时,自己自己还要发送SYN
请求信息,将SYN
位置为1,Sequence Number
为y;服务器端将上述所有信息放到一个报文段(即SYN+ACK
报文段)中,一并发送给客户端,此时服务器进入SYN_RECV
状态;
(3)第三次握手:客户端收到服务器的SYN+ACK
报文段。然后将Acknowledgment Number
设置为y+1,向服务器发送ACK
报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED
状态,完成TCP三次握手。
为了便于理解,我们忽略这些技术概念来理解三次握手:
A:“喂,你听得到吗?”A->SYN_SEND
B:“我听得到呀,你听得到我吗?”应答与请求同时发出 B->SYN_RCVD | A->ESTABLISHED
A:“我能听到你,今天balabala……”B->ESTABLISHED
完成了三次握手,客户端和服务器端就可以开始传送数据。以上就是TCP三次握手的总体介绍。
断开连接四次挥手:
当客户端和服务器通过三次握手建立了TCP连接以后,当数据传送完毕,肯定是要断开TCP连接的啊。那对于TCP的断开连接,这里就有了神秘的“四次分手”。
(1)第一次挥手:主机1(可以使客户端,也可以是服务器端),设置Sequence Number
和Acknowledgment Number
,向主机2发送一个FIN
报文段;此时,主机1进入FIN_WAIT_1
状态;这表示主机1没有数据要发送给主机2了;
(2)第二次挥手:主机2收到了主机1发送的FIN
报文段,向主机1回一个ACK
报文段,Acknowledgment Number
为Sequence Number
加1;主机1进入FIN_WAIT_2
状态;主机2告诉主机1,我“同意”你的关闭请求;
(3)第三次挥手:主机2向主机1发送FIN
报文段,请求关闭连接,同时主机2进入LAST_ACK
状态;
(4)第四次挥手:主机1收到主机2发送的FIN
报文段,向主机2发送ACK
报文段,然后主机1进入TIME_WAIT
状态;主机2收到主机1的ACK
报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,主机1也可以关闭连接了。
为了便于理解,我们忽略这些技术概念来理解三次握手:
A:“喂,我不说了。”A->FIN_WAIT1
B:“我知道了。等下,上一句还没说完。Balabala…..”B->CLOSE_WAIT | A->FIN_WAIT2
B:”好了,说完了,我也不说了。”B->LAST_ACK
A:”我知道了。”A->TIME_WAIT | B->CLOSED
A等待2MSL,保证B收到了消息,否则重说一次”我知道了”,A->CLOSED
至此,TCP的四次分手就这么愉快的完成了。
为什么要三次握手?
既然总结了TCP的三次握手,那为什么非要三次呢?怎么觉得两次就可以完成了。那TCP为什么非要进行三次连接呢?在谢希仁的《计算机网络》中是这样说的:
在书中同时举了一个例子,如下:
这就很明白了,防止了服务器端的一直等待而浪费资源。
为什么要四次挥手?
那四次分手又是为何呢?TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP是全双工模式,这就意味着,当主机1发出FIN
报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了;但是,这个时候主机1还是可以接受来自主机2的数据;当主机2返回ACK
报文段时,表示它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1的;当主机2也发送了FIN
报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。如果要正确的理解四次分手的原理,就需要了解四次分手过程中的状态变化:
FIN_WAIT_1
: 这个状态要好好解释一下,其实FIN_WAIT_1
和FIN_WAIT_2
状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1
状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN
报文,此时该SOCKET即进入到FIN_WAIT_1
状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2
状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1
状态一般是比较难见到的,而FIN_WAIT_2
状态还有时常常可以用netstat看到。(主动方)
FIN_WAIT_2
:上面已经详细解释了这种状态,实际上FIN_WAIT_2
状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你(ACK信息),稍后再关闭连接。(主动方)
CLOSE_WAIT
:这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN
报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT
状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以 close这个SOCKET,发送FIN
报文给对方,也即关闭连接。所以你在CLOSE_WAIT
状态下,需要完成的事情是等待你去关闭连接。(被动方)
LAST_ACK
: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN
报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。(被动方)
TIME_WAIT
: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FINWAIT1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT
状态,而无须经过FIN_WAIT_2
状态。(主动方)
CLOSED
: 表示连接中断。
当然,对于面向非连接的UDP则没有上述复杂的过程。
4、长连接与短连接
所谓长连接,指在一个TCP连接上可以连续发送多个数据包,在TCP连接保持期间,如果没有数据包发送,需要双方发检测包以维持此连接,一般需要自己做在线维持。
短连接是指通信双方有数据交互时,就建立一个TCP连接,数据发送完成后,则断开此TCP连接,一般银行都使用短连接。
(1)TCP与长连接和短连接
TCP协议中有长连接和短连接之分。短连接在数据包发送完成后就会自己断开。而长连接在发包完毕后,会在一定的时间内保持连接,并且可以继续后续的读写操作,即我们通常所说的Keep alive(存活定时器)功能。它的功效和用户自己实现的心跳机制是一样的。开启Keep alive功能需要消耗额外的宽带和流量,尽管这微不足道,但在按流量计费的环境下增加了费用,另一方面,Keep alive设置不合理时可能会因为短暂的网络波动而断开健康的TCP连接。
但keepalive并不是TCP规范的一部分。在Host Requirements RFC罗列有不使用它的三个理由:(1)在短暂的故障期间,它们可能引起一个良好连接(good connection)被释放(dropped),(2)它们消费了不必要的宽带,(3)在以数据包计费的互联网上它们(额外)花费金钱。然而,在许多的实现中提供了存活定时器。
UDP是面向非连接的,所以没有长连接和短连接可言。
(2)长/短连接的应用场景
长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况。每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,再次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接,如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。
而像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那后果可想而知。所以并发量大,但每个用户无需频繁操作情况下需用短连好。
(3)基于TCP协议的HTTP协议到底是长连接还是短连接(重点)?
在HTTP/1.0中,默认使用的是短连接。也就是说,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。如果客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web资源,如JavaScript文件、图像文件、CSS文件等;当浏览器每遇到这样一个Web资源,就会建立一个HTTP会话。
但从 HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头有加入这行代码:
Connection:keep-alive
在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的 TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接要客户端和服务端都支持长连接。
注意,TCP的keep alive和HTTP的Keep-alive不是同一个东西,TCP的keep alive是检查当前TCP连接是否活着;HTTP的Keep-alive是要让一个TCP连接活久点。它们是不同层次的概念。
HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。