声明: 本篇博客的学习途径主要为以下网站和课堂讲解,发博客目的仅为学习使用 http://c.biancheng.net/socket/
TCP
TCP(Transmission Control Protocol,传输控制协议)数据在传输前要建立连接,传输完毕后还要断开连接。 客户端在收发数据前要使用 connect() 函数和服务器建立连接,保证IP地址、端口、物理链路等正确无误,为数据的传输开辟通道。
TCP数据包结构
- 序号:Seq(Sequence Number),序号Seq占4个字节,用来表示数据包的序号。
- 确认号:Ack(Acknowledge Number)确认号占4个字节,向对方表示表示确认收到,Ack = Seq + 1。
- 标志位:每个标志位占用1Bit(1字节=8bit),共有6个,分别为 URG、ACK、PSH、RST、SYN、FIN,具体含义如下:
- URG:紧急指针(urgent pointer)有效。
- ACK:确认序号有效。(Acknowledge)
- PSH:接收方应该尽快将这个报文交给应用层。(PUSH)
- RST:重置连接。(Restar)
- SYN:建立一个新连接。(Synchronous 同步的)
- FIN:断开一个连接。(Finish 完成)
TCP三次握手建立连接
使用 connect() 建立连接时,客户端和服务器端会相互发送合计三个数据包 通俗理解:
[Shake 1] 套接字A:“你好,套接字B,我这里有数据要传送给你,建立连接吧。” [Shake 2] 套接字B:“好的,我这边已准备就绪。” [Shake 3] 套接字A:“我已确定,请求正式建立。”
简化理解三个数据包:
→ 建立同步 --SYN ←收到指示(与下面过程合并)–ACK ←建立同步(与上面过程合并)–SYN →收到,确定建立连接 --ACK
总结:
- 两次发送SYN,试图建立同步
- 两次收到SYN,建立同步成功
- 两次随机生成Seq序号
- 发送数据包,设置ACK,ACK = 收到的Seq+1
- 收到数据包,检测ACK,ACK为 判断 收到的ACK ?= 自身Seq+1
【问题1】为什么不能用两次握手进行连接?
答:三次握手的目的: 1.建立同步。2.确定彼此的序列号。
- 两次握手,有可能产生死锁
假定C给S发送一个连接请求分组,S收到了这个分组,并发送了确认应答分组。按照两次握手的协定,S认为连接已经成功地建立了,可以开始发送数据分组。 可是,C在S的应答分组在传输中被丢失的情况下,∴不知道S 是否已准备好,不知道S建立什么样的序列号,C甚至怀疑S是否收到自己的连接请求分组。在这种情况下,C认为连接还未建立成功,将忽略S发来的任何数据分组****,只等待连接确认应答分组。 而S在发出的分组超时后,重复发送同样的分组。 这样就形成了死锁。 - 两次握手,有可能使得失效报文生效
谢希仁版《计算机网络》中的例子是这样的,“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了
【问题2】如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
TCP 数据传输过程
TCP 四次挥手 断开连接
断开连接的必要性:
如果连接不能正常断开,不仅会造成数据传输错误,还会导致套接字不能关闭,持续占用资源,如果并发量高,服务器压力堪忧。
通俗理解:
[Shake 1] 套接字A:“任务处理完毕,我希望断开连接。” [Shake 2] 套接字B:“哦,是吗?请稍等,我准备一下。” 等待片刻后…… [Shake 3] 套接字B:“我准备好了,可以断开连接了。” [Shake 4] 套接字A:“我已确定,连接正式断开。
简化理解四个数据包:
→ 断开同步连接 – FIN ←收到指示 --ACK ←断开同步连接 --FIN →收到,正式断开 --ACK
|