星球提问 TCP三次握手这个话题,已经有很多文章涉及了。然而,今天我写这篇文章是因为我的知识星球里有球友提出了以下几个问题:
- 客户端发送完第三次握手后,是否会直接发送数据,而不管服务器是否收到?
- TCP的第三次握手是否可以携带数据?
- 如果服务端未收到客户端发送的第三次握手包,服务端如何处理客户端后续发送的数据?
以下是我的回答:
首先,对于第一个问题,客户端发送完第三次握手后,无需等待服务器确认,可以立即发送数据。这是因为TCP协议的设计允许客户端在握手完成后立即开始传输数据。
关于第二个问题,根据TCP标准协议规范(RFC793),第三次握手包是允许携带数据的。虽然在实际应用中,握手阶段通常不会携带应用层数据,但标准协议并未限制第三次握手包不能携带数据。
最后,对于第三个问题,如果服务端未收到客户端发送的第三次握手包,但客户端继续发送数据,服务端会将这个携带应用数据的包当作第三次握手。这是因为在这种情况下,客户端发送的包中通常会包含ACK标记,服务端会将其视为第三次握手的确认。
虽然我已经回答了这些问题,但为了更好地理解,我们可以进行一些实验验证。通过使用抓包工具,我们可以观察到实际的数据传输过程,以验证上述结论的正确性。
通过以上实验和分析,我们可以得出结论:客户端在发送第三次握手后可以立即发送数据,第三次握手包可以携带数据,而服务端会将携带应用数据的包当作第三次握手的确认。这些结论对于理解TCP三次握手过程的工作原理非常重要。
光理论不够,我们再来抓包看一下。下面是我使用抓包软件抓取的一个TCP连接建立的握手时序图,可以清楚地看到,在第三次握手包发送后,客户端立即开始正式的数据传输,即一个HTTP请求包。
from scapy.all import *
def tcp_test(ip, port, data):
# 第一次握手,发送SYN包
# 请求端口和初始序列号随机生成
# 使用sr1发送而不用send发送,因为sr1会接收返回的内容
ans = sr1(IP(dst=ip) / TCP(dport=port, sport=RandShort(), seq=RandInt(), flags='S'), verbose=False)
# 假定此刻对方已经发来了第二次握手包:ACK+SYN
# 对方回复的目标端口,就是我方使用的请求端口(上面随机生成的那个)
sport = ans[TCP].dport
s_seq = ans[TCP].ack
d_seq = ans[TCP].seq + 1
# 第三次握手,发送ACK确认包
send(IP(dst=ip) / TCP(dport=port, sport=sport, ack=d_seq, seq=s_seq, flags='A'), verbose=False)
# 发起GET请求
send(IP(dst=ip)/TCP(dport=port, sport=sport, seq=s_seq, ack=d_seq, flags=24)/data, verbose=False)
if __name__ == '__main__':
data = 'GET / HTTP/1.1n'
data += 'Host: www.chengtu.comn'
data += 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36n'
data += 'Accept: text/html'
data += 'rnrn'
tcp_test("150.138.151.65", 80, data)
根据实验结果和分析,我们可以得出结论:客户端在发送第三次握手包时不会携带有效的应用层数据,数据传输是在握手完成后开始的。然而,根据TCP标准协议规范,第三次握手包是允许携带数据的。
综上所述,通过实验和分析,我们得出了关于TCP三次握手的一些重要结论。这些结论对于理解TCP协议的工作原理和应用层数据传输具有重要意义。
from scapy.all import *
def tcp_test_2(ip, port, data):
# 第一次握手,发送SYN包
# 请求端口和初始序列号随机生成
# 使用sr1发送而不用send发送,因为sr1会接收返回的内容
ans = sr1(IP(dst=ip) / TCP(dport=port, sport=RandShort(), seq=RandInt(), flags='S'), verbose=False)
# 假定此刻对方已经发来了第二次握手包:ACK+SYN
# 对方回复的目标端口,就是我方使用的请求端口(上面随机生成的那个)
sport = ans[TCP].dport
s_seq = ans[TCP].ack
d_seq = ans[TCP].seq + 1
# 第三次握手,发送ACK确认包,顺带把数据一起带上
send(IP(dst=ip) / TCP(dport=port, sport=sport, ack=d_seq, seq=s_seq, flags='A')/data, verbose=False)
if __name__ == '__main__':
data = 'GET / HTTP/1.1n'
data += 'Host: www.chengtu.comn'
data += 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36n'
data += 'Accept: text/html'
data += 'rnrn'
tcp_test_2("150.138.151.65", 80, data)
为了进一步验证我们的结论,我们可以自己发送TCP数据包来模拟三次握手过程。使用工具scapy,我们可以方便地发送自定义的数据包。
通过以上实验和分析,我们可以得出结论:手动编程发送TCP数据包来实现三次握手是可行的。我们可以观察到,在第三次握手中,我们发送的GET请求已经成功传输,TCP协议仍然正常工作。
通过以上实验和分析,我们可以得出结论:如果服务端未收到客户端发送的第三次握手包,但客户端继续发送数据,服务端会将携带应用数据的包当作第三次握手的确认。这是因为在这种情况下,客户端发送的包中通常会包含ACK标记。
综上所述,通过实验和分析,我们对TCP三次握手的相关问题进行了验证和解答。这些实验结果进一步加深了我们对TCP协议的理解。
通过以上实验和分析,我们可以得出结论:如果第三次握手包服务器未收到,但客户端直接发送数据,服务器将把这个携带应用数据的包当作第三次握手的确认。这是因为在这种情况下,客户端发送的包中通常会包含ACK标记。
综上所述,通过实验和分析,我们对TCP三次握手的相关问题进行了验证和解答。这些实验结果进一步加深了我们对TCP协议的理解。
通过以上实验和分析,我们可以得出结论:如果在发送带数据的请求包后立即发送第三次握手包,服务器将把带数据的请求包当作第三次握手,而后续发送的第三次握手包将被视为重复发送的无效包并被忽略。
综上所述,通过实验和分析,我们对TCP三次握手的相关问题进行了验证和解答。这些实验结果进一步加深了我们对TCP协议的理解。