参考:
https://blog.csdn.net/zhang6223284/article/details/81414149
https://blog.csdn.net/qq_38950316/article/details/81087809
https://www.cnblogs.com/qdhxhz/p/8470997.html
TCP/IP是个协议组,可分为三个层次:网络层、传输层、应用层。
网络层有:IP协议、ICMP协议、ARP协议、RARP协议、BOOTP协议。
传输层有:TCP协议、UDP协议。
应用层有:FTP、HTTP、TELNET、SMTP、DNS等协议。
TCP,UDP,HTTP
- TCP是基于TCP协议实现的网络文本协议,属于传输层
- UDP是和TCP对等的,属于传输层
- HTTP本身就是一个协议,是从Web服务器传输超文本到本地浏览器的传送协议。基于TCP。
一、TCP
包头
- 源端口、目标端口必不可少
- 包的序号:主要用来解决乱序问题
- 确认序号:发出去的包应该由确认,这样能知道对方是否收到,如果没收到就应该重新发送,主要解决丢包问题
- 状态位:SYN是发起一个链接,ACK是回复,RST是重新连接,FIN是结束连接。TCP是面向连接的,因此需要双方维护连接的状态,这些状态位的包会引起双方的状态变更
- 窗口大小:TCP要做流量控制,需要通信双方各声明一个窗口,标识自己当前的处理能力
使用TCP协议的连接建立与断开,正常过程下至少需要发送7个包才能完成,就是我们常说的三次握手,四次挥手。
- 序列号 Sequeuece number(seq):数据包本身的序列号,初始序列号是随机的。
- 确认号 Acknowledgment number(ack):在接收端,用来通知发送端数据成功接收。
- 标志位,标志位只有为 1 的时候才有效:
SYN(synchronize):同步序列编号,表示在连接建立时用来同步序号。
ACK(Acknowledgement):确认字符,TCP协议规定,只有ACK=1时有效,也规定连接建立后所有发送的报文的ACK必须为1。
FIN(finish):用来释放一个连接。当FIN=1时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接。
建立连接:三次握手
一次TCP连接的建立需要三次握手。
第一次握手:
客户端向服务端发送请求报文;即SYN=1,ACK=0,seq=x。建立连接时,客户端发送SYN包(syn=j)到服务端,并进入SYN_SENT状态,等待服务器确认;
A:你好,我是A第二次握手:
服务器收到SYN包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYNC_RECV状态;
B:你好,A,我是B第三次握手:
客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务端进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
A:你好,B
为什么需要三次握手,而不是两次?
client发送了第一个连接的请求报文,但是由于网络不好,这个请求没有立即到达服务端,而是在某个网络节点中滞留了,直到某个时间才到达server,本来这已经是一个失效的报文,但是server端接收到这个请求报文后,还是会想client发出确认的报文,表示同意连接。假如不采用三次握手,那么只要server发出确认,新的建立就连接了,但其实这个请求是失效的请求,client是不会理睬server的确认信息,也不会向服务端发送确认的请求,但是server认为新的连接已经建立起来了,并一直等待client发来数据,这样,server的很多资源就没白白浪费掉了,采用三次握手就是为了防止这种情况的发生,server会因为收不到确认的报文,就知道client并没有建立连接。这就是三次握手的作用。
断开连接:四次挥手
第一次挥手:
TCP发送一个FIN(结束),用来关闭客户到服务端的连接。
客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。第二次挥手:
服务端收到这个FIN,他发回一个ACK(确认),确认收到序号为收到序号+1,和SYN一样,一个FIN将占用一个序号。
服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。第三次挥手:
服务端发送一个FIN(结束)到客户端,服务端关闭客户端的连接。
服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。第四次挥手:
客户端发送ACK(确认)报文确认,并将确认的序号+1,这样关闭完成。
客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
A:B,我不想玩了
B:哦,A你不想玩了啊,我知道了
(此时,只是A不想玩了,即不再发送数据,但B可能还有未发送完的数据,所以需要等待B也主动关闭)
B:A,好吧,我也不玩了,再见
A:好的,再见
为什么需要四次挥手?
关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。
可能有人会有疑问,tcp我握手的时候为何ACK(确认)和SYN(建立连接)是一起发送。挥手的时候为什么是分开的时候发送呢?因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭 SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。
客户端突然挂掉了怎么办?
正常连接时,客户端突然挂掉了,如果没有措施处理这种情况,那么就会出现客户端和服务器端出现长时期的空闲。解决办法是在服务器端设置保活计时器,每当服务器收到客户端的消息,就将计时器复位。超时时间通常设置为2小时。若服务器超过2小时没收到客户的信息,他就发送探测报文段。若发送了10个探测报文段,每一个相隔75秒,还没有响应就认为客户端出了故障,因而终止该连接。
累计确认
为了保证顺序性,每个包都有一个 ID。在建立连接的时候会商定起始 ID 是什么,然后按照 ID 一个个发送,为了保证不丢包,需要对发送的包都要进行应答,当然,这个应答不是一个一个来的,而是会应答某个之前的 ID,表示都收到了,这种模式成为累计应答或累计确认。
为了记录所有发送的包和接收的包,TCP 需要发送端和接收端分别来缓存这些记录,发送端的缓存里是按照包的 ID 一个个排列,根据处理的情况分成四个部分:1、发送并且确认的;2、发送尚未确认的;3、没有发送等待发送的;4、没有发送并且暂时不会发送的。这里的第三部分和第四部分就属于流量控制的内容。
对于接收端来讲,它的缓存里面的内容要简单一些:1、接收并且确认过的;2、还没接收,但是马上就能接收的;3、还没接收,但也无法接收的。
TCP为什么是可靠连接
- 通过TCP连接传输的数据无差错,不丢失,不重复,且按顺序到达。
- TCP报文头里面的序号能使TCP的数据按序到达。
- 报文头里的确认序号能保证不丢包,累计确认及超时重传机制。
- TCP拥有流量控制及拥塞控制的机制。
二、UDP
包头
特点
- 不需要大量的数据结构、处理逻辑和包头字段
- 不会建立连接,但会监听指定端口,谁都可以传给它数据,它也可以传给任何人数据,可以同时传给多个人数据
- 不会根据网络的情况进行拥塞控制,无论是否丢包,它该怎么发还是怎么发
主要应用场景
- 需要资源少,网络情况稳定的内网,或者对丢包不敏感的应用。比如DHCP就是基于UDP协议的
- 不需要一对一沟通、建立连接,而是可以广播的应用。因为它不面向连接,所以可以做到一对多,承担广播或多播的协议
- 需要处理速度快,可以容忍丢包,但是即使网络拥塞,也毫不退缩、一往无前的时候
基于UDP的几个例子
- 直播。直播对实时性要求比较高,宁可丢包,也不要卡顿,所以很多直播应用都基于UDP实现自己的视频传输协议
- 实时游戏。游戏的特点也是实时性比较高,在这种情况下,采用自定义的可靠的 UDP 协议,自定义重传策略,能够把产生的延迟降到最低,减少网络问题对游戏造成的影响
- 物联网。一方面,物联网领域中断资源少,很可能知识个很小的嵌入式系统,而维护 TCP 协议的代价太大了;另一方面,物联网对实时性的要求也特别高。比如 Google 旗下的 Nest 建立 Thread Group,推出了物联网通信协议 Thread,就是基于 UDP 协议的
TCP和UDP对比
- TCP是面向连接的,UDP是面向无连接的
在互通之前,面向连接的协议会先建立连接,如TCP三次握手,但UDP不会 - UDP程序结构较简单
- TCP是面向字节流的,UDP是基于数据报的
- TCP保证数据正确性,UDP可能会丢包
- TCP保证数据顺序,UDP不保证