客户端:Ubuntu 16.04 ,IP:192.168.78.128 ,简称为客户端A
服务端:Ubuntu 16.04 ,IP:192.168.78.130,简称为服务端B
抓包利器-大白鲨 Wireshark 以及 Linux 下的抓包命令 tcpdump
GCC:5.4.0
因为 Wireshark 的图标就很像一条大鲨鱼的鱼鳍,所以又叫大白鲨,不信你看看
大白鲨
这里简单介绍下 TCP 最经典的三次握手与四次挥手
三次握手四次挥手
成功建立连接后,客户端与服务端就开始进行数据交互。客户端发送数据,服务端回复收到该数据,然后交替进行下去。
当客户端和服务端通过三次握手建立 TCP 连接进行可靠数据传输后,当数据传送完毕,肯定是要断开TCP连接,这里就有了神秘的“四次挥手”。
这里主要使用的是尹圣雨[韩]的著作《TCP/IP网络编程》第 4 章中的简易版回声服务器来进行实验。
所谓回声服务端,就像小时候在回声山谷中玩的游戏一样,你朝山谷中大吼一声“啊”,然后山谷也会给你一个“啊”。回声服务端就是你向服务端发送一个“hello world”,回声服务端也向你回复一个“hello world”。
1、将客户端程序 echo_client.c 放在客户端 A 中,将服务端程序 echo_server.c 放在服务端 B 中
2、在客户端 A 中开启一个命令行窗口,使用 tcpdump 命令监控 A、B 之间的网络通信,并将消息保存为 pacp 文件,方便后续进行抓包分析
3、在服务端 B 中编译程序 echo_server.c,开启服务端程序 echo_server,监听指定端口 2333
这里的端口号可以自己指定,在 1025-65535 之间都可以,主要是因为0-1024已经被系统占用了,比如http的80端口,ssh的22端口。而 Linux 下默认端口数在65535个,所以自己可以指定的端口号就在1025-65535之间。
4、在客户端 A 中编译程序 echo_client.c,并且开启客户端程序 echo_client,指定通话 IP 以及端口号,我在这里就是服务端 B 的IP:192.168.78.130以及 2333 端口号了
5、在客户端 A 中发送消息“hello”,然后按 Q 退出即可
6、通信完毕,将 2 中保存的文件转存到 Windows 环境下,使用大白鲨 Wireshark 进行网络数据包分析。
7、分析抓到的数据包文件
说了那么多,终于可以开始开干了!
1、将echo_client.c 、echo_server.c分别放在客户端A:192.168.78.128 以及服务端B:192.168.78.130 中。
客户端A
服务端B
2、 在客户端A中新开一个命令行窗口,输入命令:sudo tcpdump -i any tcp and host 192.168.78.130 and port 2333 -w message.pcap
1、由于tcpdump命令需要管理员权限,所以需要加上sudo命令进而获取管理员权限。 2、这段命令的大概含义就是监控客户端 A:192.168.78.128,和服务端 B:192.168.78.130 之间在端口号2333 上的基于TCP的数据交换,并且保存为 message.pcap 文件
tcpd数据包保存命令
可以看到,我们在输入该条命令后,需要首先输入 Linux 下的密码获取管理员权限,然后就开始监听客户端 A:192.168.78.128,与服务端 B:192.168.78.130之间在端口号2333上的TCP通信了。
3、接下来,我们进入含有 echo_server.c的文件夹,将服务端B的程序进行编译,编译命令为 gcc echo_server.c -o echo_server,可以看到当前文件夹下出现了 echo_server 程序
编译服务器程序
接下来,开始监听我们预先设置好的端口号 2333,命令为:./echo_server 2333,服务端开始正式监听。
运行服务器程序
4、服务端 B 设置完毕,我们开始转战客户端 A ,在 2 中使用 tcpdump 命令监听的那个端口号不要关闭,千万不要关闭,我们在客户端 A 中另外新开一个命令行。
跟服务端 B 中类似,首先将客户端 A 中的程序echo_client.c进行编译,编译命令:gcc echo_client.c -o echo_client
编译客户端程序
跟服务端 B 中类似,我们在客户端 A 中开启客户端程序echo_client,指定通话IP :192.168.78.130及端口号 2333
命令为./echo_client 192.168.78.130 2333
运行客户端程序
可以看到出现 “Connected…..”字样,说明我们已经走完长征两万五千公里,成功会师啦!
客户端 A 与服务端 B 终于成功连接了,这个时候我们再转去看一下服务端 B 的状态。
服务器程序状态
在服务端 B 的监听窗口也出现了“Connect client 1”字样,换句话说,在服务端看来,有一个客户端与它成功建立连接了。
5、下一步就可以开始通信了,我们在客户端 A 中发送“hello”字样。
在客户端A发送消息
可以看到,我们在客户端 A 中发送了一条消息“hello”, 服务端 B 也给了我们一个消息“hello”,这也就是我们上文中提到的回声服务端了。
接下来,我们按照提示,输入“Q”结束本次通话。
退出客户端A
至此,本次通话结束。
6、最后我们在 2 中开启 tcpdump 命令监控的界面中,按下 ctrl+ c ,结束监听。
保存抓包文件
可以看到,提示我们一共成功捕获了10 个packets,没有数据包丢失。接下来,我们将捕获文件 message.pacp传输到 Windows 下开始进行抓包分析。
可以看出一共 10 个数据包,也对应了上文中我们在 Linux 下通过tcpdump命令抓到的数据包个数。其中序号 1-3 为三次握手的数据包,序号 4-7 为两次数据交换的数据包,8-10 为三次挥手的数据包。
抓到的10个数据包
问题1:4-7 为什么是两次数据交换呢? 回答1:我们的回声服务端就是你发送什么数据过去,服务端发送什么数据回来,所以第一次数据交换:客户端A发送数据”hello“到服务端B,B回复 确认收到。这也对应着4、5数据包;第二次数据交换:服务端B发送数据”hello“到客户端A,A回复 确认收到。这也对应着6、7数据包。 问题2:说好的四次挥手呢?这里怎么只有三次了? 回答2: 因为服务端收到客户端的 FIN 后,服务端也可以同时关闭连接,这样就可以把 ACK 和 FIN 两个包合并到一起发送,这样可以节省一个网络包,“四次挥手”变成了“三次挥手”。这样可以节省网络资源,省时又省力。而通常情况下,服务端收到客户端的 FIN 后,很可能还没发送完数据,所以就会先回复客户端一个ACK 包,完成所有数据包的发送后,才会发送 FIN 包,也就是“四次挥手“了。
三次挥手过程
第一次握手,序号为1,客户端A:192.168.78.128 向服务端B:192.168.78.130 发送SYN请求包,seq为1796975076。
第二次握手,序号为2,服务端 B:192.168.78.130 向客户端A:192.168.78.128 发送 SYN、ACK 请求回复包,seq为1222412335,ack为1796975077,也就是第一次握手中的 seq+1。
第三次握手,序号为3,客户端A:192.168.78.128 向服务端B:192.168.78.130 发送 ACK 确认包,seq为1796975077,ack为为1222412336,也就是第二次握手中的 seq+1。
第一次数据交互:
第一次数据交互
序号为4,客户端A:192.168.78.128 向服务端B:192.168.78.130 发送 push 消息包,可以看到下方的数据解析为“hello”,并且数据长度 len = 6。
可能有些小伙伴问“hello不是一共5个字符吗?长度应该为5啊。”len = 6是因为“hello“长度为5,再加上结尾的‘\0’,加起来一共就是6了
序号为5,服务端B:192.168.78.130 向客户端A:192.168.78.128 发送 ACK 确认包,表示已经收到该消息。
第二次数据交互:
第二次数据交互
序号为6,服务端B:192.168.78.130 客户端A:192.168.78.128发送push消息包,可以看到下方的数据解析为“hello”,并且 len = 6。
序号为7,客户端A:192.168.78.128 向服务端B:192.168.78.130 发送ACK确认包,表示已经收到该消息。
正式的四次挥手如下图所示:
标准的四次挥手
我们所抓到的三次挥手如下所示:
我们抓包抓到的三次挥手
第一次挥手,序号为8:客户端A:192.168.78.128 向服务端B:192.168.78.130 发送 FIN 请求断开连接包,表示主动请求断开链接。
第二三次挥手,序号为9:服务端B:192.168.78.130 向 客户端A:192.168.78.128发送 FIN、ACK 确认并请求断开消息包,表示收到上次断开连接的请求,并请求断开服务端到客户端的链接。
可以看出,我们所抓的包中,将第二次挥手和第三次挥手合并为一个数据包了,也就是192.168.78.130->192.168.78.128的包中既有FIN也有ACK,所以这也是三次挥手而不是四次挥手的原因。
第四次挥手,序号为 10:客户端A:192.168.78.128 向服务端B:192.168.78.130 发送 ACK 确认包,表示收到服务端发送过来的请求断开连接消息,并给予回复。
巨人的肩膀
https://my.oschina.net/u/658658/blog/417739 《TCP/IP网络编程》- 尹圣雨[韩] 《Wireshark网络分析就这么简单》- 林沛满 《Wireshark网络分析的艺术》- 林沛满 《计算机网络-自顶向下方法》- ames F. Kurose、Keith W. Ross 《TCP/IP详解 卷1:协议》- kevin R.Fall W.Richard Stevens