linux网络编程3——TCP协议

参考资料:
《黑马linux网络编程》
《计算机网络自顶向下方法》
https://www.zhihu.com/question/53658729/answer/498879547问题下小林coding的回答https://www.zhihu.com/question/24853633/answer/115173386问题下车小胖的回答


一、TCP协议

基本介绍

由于网络层具有不稳定性,可能导致数据无法到达对端,tcp协议应运而生。

tcp与udp

udp:对于网络层的不稳定传输选择不弥补,我们称之为udp(不可靠无连接报文传输)

tcp:做完全弥补,称之为面向连接的可靠数据包传递。(数据传输前在两端建立通路,这也是为什么之前提到若采用tcp,数据包经过的路由节点是相同的)

tcp和udp的协议的共同点在于,都是依靠下层不稳定通信信道实现的。但在传输层逻辑通信上tcp实现了可靠传输。tcp和udp报文段格式都有校验和字段(ip段格式里也有),他的作用是错误校验,但是不支持错误恢复。校验和算法并不能保证百分百的纠错,但好在数据链路层有更强大的CRC算法检验(这部分我了解比较少,不再叙述。)

协议选择方面,我们通过看两者优缺点来分析:
1.TCP实现了可靠传输,但是必须提前建立连接。udp无需任何准备即可进行数据传输,不会引入建立时间的时延。(对于http协议来说,我们更关注文本数据的可靠性,因此采用tcp)
2.TCP需要在端系统中维护连接状态,包括接受和发送缓存,拥塞控制参数以及序号和确认号的参数。而udp不维护连接状态。因此,某些专门用于某种特定应用的服务器当应用程序运行在udp上时一般能支持更多活跃客户。
3.分组首部开销tcp占20 byte,而udp仅有8 byte。
4.udp关于发送什么数据以及何时发送的应用层控制更为精细。udp只负责发送,而tcp存在拥塞控制机制和可靠传输机制,如果出现拥塞或者错误,需要重发该数据包而并不关心这一过程需要多少时间。对于更关注实时性的应用,我们并不希望过分延迟报文段的发送,tcp并不是特别适合这些应用。

tcp通信时序

先来看建立连接的过程。
第一步,客户端首先发送一个特殊的tcp报文段,该报文段不含应用层数据,但报文段首部的flags field位图的代表SYN的位设置为1。另外,客户端会随机选择一个初始序号(client_isn)将其放置于此报文段的序号字段中。该报文段被封装在一个ip数据包中发送给服务器(随机选择的原因见下文)。

第二步,一旦包含TCP SYN报文段的ip数据报到达服务端,服务器将提取TCP SYN报文段,为该TCP连接分配缓存和变量(使得tcp易受到SYN洪泛攻击),并向客户端发送允许连接的报文段。这个允许连接报文段同样不包含应用层数据,但报文段的首部多了3个重要信息:
1.SYN 位被置为1,ACK位被置为1
2.确认号字段被置为client_isn(初始序号)+1
3.服务器选择自己的初始序号(server_isn),放到tcp报文段首部的序号字段。

第三步,收到SYNACK报文段后,客户也要给该连接分配缓存和变量,并向服务器发送一个报文段。这个报文段对服务器允许连接的报文段进行确认(将server_isn+1放到确认字段以进行确认,同时自己的seq字段变为client_isn+1)。此时连接已经建立,SYN置为0,这时ACK为1。这一阶段可以在报文段负载中携带客户到服务器的数据。在完成三次握手后,此后TCP报文段中的SYN都置为0。

上述过程,被称为三次握手。
注:1.在之前系列中我贴过视频中给的tcp报文段格式,那里的flags位图与《计算机网络自顶向下》中的不太一样,原因是书中出于完整性考虑多了两个标志位,但实践中并没有使用,也就是说实际上是8 bit 。
2.SYN洪泛攻击:服务器响应了一个收到的SYN,分配并初始化连接变量和缓存,发送SYNACK并等待客户端的ACK报文段,如果此时客户端不发送ACK完成三次握手的第三步,通常一分钟后服务器终止该半开连接并回收资源。然而如果攻击者短时间内发送大量TCP SYN报文段却不完成第三次握手,服务器会不断为这些连接分配资源,导致资源消耗殆尽。

数据传送时,ack位为1,使用累计确认法。

而断开连接的过程,我们称为四次握手(允许半关闭)。流程如下:
若客户端想关闭连接,会向服务器发送一个特殊的TCP报文段,其中flags域中的FIN位被设为1。服务器接收到报文就会回送一个确认报文段(此时是半关闭状态,客户端关闭服务器不关闭,客户端这时依然可以接受数据),然后发送一个服务端终止报文段,FIN置为1。最后,客户端会回复一个确认报文段。

一些有趣问题和讨论

1.IP数据报最大上限65535字节,而以太网帧容纳上限1500字节,这是为什么?
答:ip数据报确实上限65535,然而按照TCP/IP协议做了封装之后一个数据报只能携带1500(MTU限制了数据链接层上可以传输的数据包的大小,也因此限制了网络层的数据报大小),因为ip层协议受制于以太网帧协议。当然会有人问为什么当初不设计的传输的更大一些呢,这主要是考虑到在数据传输过程中说如果发生丢包现象,1500的重传时延会更小。

2.为什么要有序列号,为什么采用随机数初始化序列号?
答:有序列号是因为,假设ab通信,b端回复的ack丢失或出错,a端要重发数据包,如果没有序号,b端不知道到来的数据包是新的还是重发的。采用随机数是因为,我们并不能保证每次连接都能通过四次挥手来正常关闭连接,因此历史报文被下一个相同四元组的连接接收。图示见参考资料原帖回答。

3.为什么是三次握手,不是两次和四次?
答:tcp握手过程实际是保证通信双方都确认对方收到了自己的那个初始的随机的序列号。假设AB双方通信,A选择初始序列号并发送自己的TCP SYN报文段到B端,此时B收到A的初始序列号并记录到本地,确认序号就填这个+1。紧接着选择自己的初始序号发送给A。可以看到后两步是可以合并的。
紧接着A收到后,再回复给B确认信息(确认序号server_isn+1)。
两次的话,就没有上面的那最后一个回复信息了,B无法知道A确实收到了自己的初始序列号。

二、

おすすめ

転載: blog.csdn.net/Haroldhyc/article/details/122507195