zoukankan      html  css  js  c++  java
  • 用Wireshark分析Socket连接建立的过程

    0. 安装Wireshark,但是默认情况下,Wireshark无法捕获127.0.0.1的报文

    解决方案:安装npcap,替换默认的winpacp,重新启动Wireshark,就可以看到一个名字中含有Loopback的接口,针对它来抓包就行了

    1. 用telnet向未被监听的9090端口发送连接请求

    telnet窗口一闪而过,抓包结果如下

    可以看出,未被监听的端口会直接返回RST包,导致Telnet无法正常建立连接。

    2. 开启echo server监听9090端口,然后使用telent向9090端口发送连接请求

    可以清楚的看到TCP的三次握手过程,现在Telnet已经与echo server建立了TCP连接了

    3. 在第二步的基础上,使用telenet向echo server发送数据

    我在Telnet里输入了abc三个字符,下图是抓包结果

    可以看到一共有12个包,每四个包为一组,对应于Telnet中的一次输入

    这四个包分别对应于 客户端发送字符->服务器ack->服务器发送echo->客户端ack

    4. 在BIO模式的echo server中插入断点

    使用BIO模式的echo server,但是在调用ServerSocket.accept()方法处下断点,让程序跑到此处停顿。

    然后启动Telnet向服务器发送数据,结果如下:

    可以看到在这种情况下,居然可以完成三次握手协议,正常建立连接(但此时服务端正卡在accept()方法上)

    对于客户端后续发送的数据,服务端也能及时发送ack,只是无法发送echo罢了。一旦放开echo server的断点,服务器就能正常工作了,前面没收到echo的数据也不会丢失。

    5. 在NIO模式的echo server中插入断点

    与BIO模式相近,ServerSocketChannel只要与端口绑定,对于Telnet的连接请求,无需服务端调用accept方法就能完成三次握手。

    客户端后续发送的数据,服务端也能正常返回ack。

    6. 为什么只需要完成监听端口,无需调用accept方法就能完成三次握手呢?

    我之前的想法是:accept方法在收到客户端发过来的syn包后就会从阻塞状态中退出,在此同时返回ack+syn包,完成三次握手(这个想法太奇怪了)

    实际上是tcp底层维护了两个队列:半连接队列与全连接队列。操作系统收到Telnet的tcp连接请求后会自动完成三次握手建立TCP连接,然后将这个连接放到全连接队列中。而accept方法则是将TCP连接从这个全连接队列中提取出来罢了。

    简单测试一下,在创建ServerSocket对象的时候,将backlog设置为1,然后将断点设置在accept方法处(不让程序从TCP全连接队列中提取连接)。然后开启两个Telnet客户端,结果第一个Telnet可以正常连接,第二个Telnet直接闪退了。

    抓包如下图所示:

    可以清楚的看到从6078到9090的TCP连接成功的完成了三次握手,从6079到9090的TCP连接则握手失败了。

    参考资料:

    关于TCP 半连接队列和全连接队列

  • 相关阅读:
    CC++ 文件操作
    loadrunner之Paramater在负载测试中的数据生成规则
    loadrunner关联及web_reg_save_param方法浅析
    mysql union 与 union all 语法及用法
    sql 语句中as的用法和作用
    数据库主从复制和读写分离
    《剑指offer》算法题第十二天
    《剑指offer》算法题第十一天
    《剑指offer》算法题第十天
    《剑指offer》算法题第九天
  • 原文地址:https://www.cnblogs.com/stevenczp/p/7501779.html
Copyright © 2011-2022 走看看