最近在看《unix网络编程》刚好总结下tcp中的三次握手和四次挥手。 一、tcp中的三次握手和四次挥手的过程 TCP三次握手: 1.连接请求由客户端发起,发送一个SYN分节,Seqence number为0(也就是图中的J) 2.服务端接收到客户的SYN之后,确认(ACK)客户的SYN,同时也发送一个SYN分节。此时Acknowledgment number=1(J+1) 3.客户端确认服务端的SYN。 下图为tcp分节的模式(图来源于网络) TCP四次挥手:上图为客户端执行主动关闭的情况,客户,服务端都可以执行主动关闭 1.客户端调用close
,该端称为主动关闭,发送FIN分节. 2.接收到这个FIN分节的一端称为被动关闭。这个FIN由TCP确认。它的接收也作为一个文件结束符传递给接收端应用进程(放在已排队等候该应用进程接收的任何其它数据之后),因为FIN的接收意味着接收端应用进程在相应连接上现无额外数据可接收。 3.一段时间后,接收到这个文件结束符的应用进程将调用close关闭它的socket。同时也会发一个FIN分节。 4.主动关闭那一端,发送ACK确认FIN。
步骤2和步骤3都由被动关闭一端发出,有可能会被合并成一个分节。
二、通过tcpdump抓包进行分析 1.使用socket
编写tcp客户端和服务程序。
# server.py
import socket
bind_ip ="0.0.0.0"
bind_port = 8080
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((bind_ip, bind_port)) #将指定的ip和port绑定到该套接字
server.listen(3) #调用listen函数把该套接字转换成一个监听套接字,参数3指定系统内核允许在这个监听描述符上排队的最大客户连接数
while True:
client, addr = server.accept() #等待客户端连接,完成三路握手后返回一个已连接描述符,accept函数为每个连接到本服务器的客户端返回一个新的新描述符
rcv = client.recv(1024)
print(rcv)
client.close()
# client.py
import socket
host = "127.0.0.1"
port = 8080
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((host, port))
client.close()
2.在linux终端中执行命令tcpdump -i lo port 8080 -w tcphandshake.pcap
3.在两个窗口分别执行python server.py
,python client.py
4.将抓包的在wireshake中打开。
可以看到和上面描述的过程是一致的,四次挥手步骤2和步骤3合并成了一个分节。
5.查看分节中的详细信息。 - tcp三次握手中客户端发送的SYN分节。 客户端会告诉对端它的最大分节大小(maximum segment size—MSS),就是在这个连接中每个TCP分节可以接受的最大数据量。 告诉对端它的窗口大小是多少。 - tcp四次挥手,步骤2和步骤3发送的分节(合并成了一个分节),图如下。
三,https协议握手过程
https握手在tcp的三次握手的基础上加上了TLS/SSL安全基础层,用于在HTTP协议上安全地传输数据。
1.客户端首次请求服务端,告诉服务端自己支持的协议版本,支持的加密算法及压缩算法,并生成一个客户端随机数(Client Random)并告知服务端
2.服务端确认双方使用的加密算法,并返回组客户端证书及一个服务端生成的服务端随机数(Server Random)
3.客户端收到证书后,首先验证证书的有效性,然后生成一个新的随机数(Premaster Secret),使用数字证书中的公钥来加密这个随机数,并发送给服务端。
4.服务端接收到已加密的随机数后,使用私钥进行解密,获取这个随机数(Premaster Secret)
最后服务端和客户端根据约定的加密算法,使用前面的3个随机数(Client Random,Server Random, Premaster Secret),生成对话密钥,用来加密接下来的事个会话过程。
总结: 看十遍,不如实际动手操作一遍!!!
Ref: 1.《unix网络编程-套接字》
2.https://www.freesoft.org/CIE/Course/Section4/8.htm
3.https://cs.fit.edu/~mmahoney/cse4232/tcpip.html