简介

Wireshark是一个网络抓包分析软件,当线上出现各种连接相关的问题,如连接不复用,大量CLOSE_WAIT时,可以方便的使用Wireshark抓包软件进行抓包分析

安装

Wirewark在windows系统上默认使用的是WinPcap来抓包的,只能看到经过网卡的流量,看不到访问localhost的流量,可先安装Npcap,安装Wirewark时再选择不安装WInPcap即可抓localhost的包

基本使用

window下,直接只用wireshark客户端进行抓包



Linux下,使用tcpdump产生pcap文件,再通过wireshark导入分析

tcpdump -s0 host 192.168.162.103 and port 9999 -w my.pcap

典型场景分析

服务端代码:

public class SocketServer {
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket();
server.bind(new InetSocketAddress((InetAddress)null, 9999));
Socket socket = server.accept();
// socket.setKeepAlive(true); 默认情况下不进行心跳检测
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
Runtime.getRuntime().addShutdownHook(new Thread(()-> {
try {
socket.close();
server.close();
} catch (IOException e) {
System.out.println("close exception" + e);
}
}));
while(true) {
byte[] bytes = new byte[1024];
int size = in.read(bytes);
System.out.println("server read " + new String(Arrays.copyOf(bytes, size)));
out.write("hello client".getBytes());
out.flush();
}
}
}

客户端代码:

public class SocketClient {
public static void main(String[] args) throws Exception {
Socket socket = new Socket("192.168.162.105", 9999);
OutputStream out = socket.getOutputStream();
out.write("hello server".getBytes());
out.flush(); InputStream in = socket.getInputStream();
byte[] bytes = new byte[1024];
int size = in.read(bytes);
System.out.println("server read " + new String(Arrays.copyOf(bytes, size)));
// Thread.sleep(22 * 1000); 休眠一段时间使得服务端进行心跳检测
out.close();
in.close();
socket.close();
}
}

1 观察三次握手、四次挥手



其中四次挥手只有3个tcp分组原因:四次挥手的时候,两个方向的断开是独立的,每个方向发送一个FIN,对方回复一个ACK,但同时,TCP规定ACK可以捎带在其他数据包当中,所以你看到的主动断开连接一方本应收到的ACK,是被对方的FIN包捎带过来的,就变成了三个包。并不是所有的情况下都是这样,典型的一种情况是,主动断开的一方发送FIN之后,被动一方仍然有数据要继续发送,就会先ACK这个FIN,然后继续发送数据(在此过程中主动断开一方仍然会继续ACK这些数据),直到数据发送完毕之后再发送FIN并接收对方的ACK。

2 观察tcp心跳检测机制(放开注释)

tcp心跳服务端参数说明

2.1 模拟客户端一段时间不传输数据



服务器net.ipv4.tcp_keepalive_intvl = 10,以上代码客户端sleep了22s,因此服务端进行了2次心跳检测

2.2 模拟MySQL Client突然掉线,抓取Server端

  • 最后一次正常请求后10s,服务端开始发送心跳包
  • 心跳包间隔3秒,发送3次
  • 3次后,服务端关闭连接

3 线上CLOSE_WAIT问题

在被动关闭连接情况下,在已经接收到FIN,但是还没有发送自己的FIN的时刻,连接处于CLOSE_WAIT状态,由此分析可知通常是被动关闭方代码问题。

线上应用程序引入连接池后,访问clickhouse出现CLOSE_WAIT

  • 可以看到客户端一直没有回复FIN,研究clickhouse客户端源码实现发现clickhouse底层基于HttpClient实现JDBC接口,由于Http服务端并不会永久保持连接,当服务端超过Keep-Alive时间后会主动关闭连接,而客户端使用连接池后,不会释放关闭连接,导致客户端CLOSE_WAIT
  • 因此通过增加服务端和客户端的http层Keep-Alive时间,可以缓解这个问题,但是并不能根本解决
  • 由于HttpClient本身可以支持多个连接,所以对一个Connection进行管理,即可支持连接池,后续舍弃了Druid连接池,自己进行了客户端JDBC封装

此问题中客户端没有关闭连接,发送FIN导致客户端处于CLOSE_WAIT状态,理论上服务端没有收到FIN,应该处于FIN_WAIT_2的状态,但实际观察发现服务端已经完全关闭了,查看TCP配置发现,FIN_WAIT_2可通过tcp_fin_timeout配置FIN_WAIT_2超时时间,一旦超时会直接进入CLOSED状态,而不经过TIME_WAIT

4 服务端TIME_WAIT

主动关闭TIME_WAIT,被动关闭CLOSE_WAIT

TIME_WAIT时间配置内核没有透出,如果要改需重新编译内核

查看内核源码发现,默认TIME_WAIT时间为60s

https://yq.aliyun.com/ziliao/256040

Java客户端Socket常用配置(进程级别配置)

  • socket.setKeepAlive(true);

    是否开启tcp心跳检测机制,默认不开启,开启后会根据OS tcp_keepalive_time、tcp_keepalive_intvl、tcp_keepalive_probes进行心跳检测
  • socket.setReuseAddress(true);

    允许复用处于TIME_WAIT的socket
  • socket.setTcpNoDelay(true);在默认情况下,客户端向服务器发送数据时,会根据数据包的大小决定是否立即发送。当数据包中的数据很少时,如只有1个字节,而数据包的头却有几十个字节(IP头+TCP头)时,系统会在发送之前先将较小的包合并到较大的包后,一起将数据发送出去。在发送下一个数据包时,系统会等待服务器对前一个数据包的响应,当收到服务器的响应后,再发送下一个数据包,这就是所谓的Nagle算法;在默认情况下,Nagle算法是开启的。

    这种算法虽然可以有效地改善网络传输的效率,但对于网络速度比较慢,而且对实现性的要求比较高的情况下(如游戏、Telnet等),使用这种方式传输数据会使得客户端有明显的停顿现象。因此,最好的解决方案就是需要Nagle算法时就使用它,不需要时就关闭它。而使用setTcpToDelay正好可以满足这个需求。当使用setTcpNoDelay(true)将Nagle算法关闭后,客户端每发送一次数据,无论数据包的大小都会将这些数据发送出
  • socket.setSoLinger(true, 0);

  • socket.setSoTimeout(soTimeout);

    配置inputstream一个阻塞read的超时时间

Linux常用TCP参数(OS级别配置)

  • net.ipv4.tcp_keepalive_time

    当keepalive起用的时候,TCP发送keepalive消息的频度,单位为秒,缺省是7200秒(即2小时)
  • net.ipv4.tcp_keepalive_intvl

    keepalive探测包的发送间隔
  • net.ipv4.tcp_keepalive_probes

    如果对方不予应答,探测包的发送次数
  • net.ipv4.tcp_timestamps

    为1表示开启TCP时间戳,用来计算往返时间RTT(Round-Trip Time)和防止序列号回绕
  • net.ipv4.tcp_tw_reuse

    为1表示允许将TIME-WAIT的句柄重新用于新的TCP连接
  • net.ipv4.tcp_tw_recycle

    为1表示开启TCP连接中TIME-WAIT的快速回收,NAT环境可能导致DROP掉SYN包(回复RST),不要轻易与net.ipv4.tcp_timestamps一起开启
  • net.ipv4.tcp_fin_timeout

    FIN_WAIT_2状态的超时时长
  • net.ipv4.tcp_syncookies

    为1时SYN Cookies,当SYN等待队列溢出时启用cookies来处理,可防范少量SYN攻击
  • net.ipv4.tcp_max_tw_buckets

    保持TIME_WAIT套接字的最大个数,超过这个数字TIME_WAIT套接字将立刻被清除并打印警告信息
  • net.ipv4.ip_local_port_range

    设定tcp客户端发起连接随机端口范围,默认32768,61000,这个配置限制了此机器访问外部机器的连接数目
  • net.ipv4.tcp_max_syn_backlog

    端口最大backlog内核限制,防止占用过大内核内存
  • net.ipv4.tcp_syn_retries

    对一个新建连接,内核要发送多少个SYN连接请求才决定放弃,不应该大于255
  • net.ipv4.tcp_retries1

    放弃回应一个TCP连接请求前﹐需要进行多少次重试,RFC规定最低的数值是3,这也是默认值
  • net.ipv4.tcp_retries2

    在丢弃激活(已建立通讯状况)的TCP连接之前﹐需要进行多少次重试,默认值为15
  • net.ipv4.tcp_synack_retries

    TCP三次握手的SYN/ACK阶段重试次数,缺省5
  • net.ipv4.tcp_max_orphans

    不属于任何进程(已经从进程上下文中删除)的sockets最大个数,超过这个值会被立即RESET,并同时显示警告信息
  • net.ipv4.tcp_orphan_retries

    孤儿sockets废弃前重试的次数,缺省值是7
  • net.ipv4.tcp_mem

    内核分配给TCP连接的内存,单位是page:

    第一个数字表示TCP使用的page少于此值时,内核不进行任何处理(干预),

    第二个数字表示TCP使用的page超过此值时,内核进入“memory pressure”压力模式,

    第三个数字表示TCP使用的page超过些值时,报“Out of socket memory”错误,TCP 连接将被拒绝
  • net.ipv4.tcp_rmem

    为每个TCP连接分配的读缓冲区内存大小,单位是byte
  • net.ipv4.tcp_wmem

    为每个TCP连接分配的写缓冲区内存大小,单位是byte:

    第一个数字表示,为TCP连接分配的最小内存,

    第二个数字表示,为TCP连接分配的缺省内存,

    第三个数字表示,为TCP连接分配的最大内存(net.core.wmem_max可覆盖该值)

参考文档:

https://www.cnblogs.com/wangjq19920210/p/8440824.htm

https://www.zhihu.com/question/55890292

https://yq.aliyun.com/articles/581106

http://elf8848.iteye.com/blog/1739598

https://segmentfault.com/a/1190000012345710

TIME_WAIT很好的文章:

https://jin-yang.github.io/post/network-tcpip-timewait.html

tcp_timestamps抓包分析文章:

http://www.bubuko.com/infodetail-1650846.html

Wireshark抓包与常见问题解决的更多相关文章

  1. 接口测试之——Charles抓包及常见问题解决(转载自https://www.jianshu.com/p/831c0114179f)

    简介 Charles其实是一款代理服务器,通过成为电脑或者浏览器的代理,然后截取请求和请求结果达到分析抓包的目的.该软件是用Java写的,能够在Windows,Mac,Linux上使用,安装Charl ...

  2. Wireshark抓包分析/TCP/Http/Https及代理IP的识别

    前言 坦白讲,没想好怎样的开头.辗转三年过去了.一切已经变化了许多,一切似乎从没有改变. 前段时间调研了一次代理相关的知识,简单整理一下分享之.如有错误,欢迎指正. 涉及 Proxy IP应用 原理/ ...

  3. Wireshark抓包工具使用教程以及常用抓包规则

    转载:http://fangxin.blog.51cto.com/1125131/735178 Wireshark是一个非常好用的抓包工具,当我们遇到一些和网络相关的问题时,可以通过这个工具进行分析, ...

  4. TCP协议基础知识及wireshark抓包分析实战

    TCP相关知识 应swoole长连接开发调研相关TCP知识并记录. 数据封包流程 如图,如果我需要发送一条数据给用户,实际的大小肯定是大于你发送的大小,在各个数据层都进行了数据的封包,以便你的数据能完 ...

  5. Wireshark抓包数据:理解与分析

    wireshark是一个非常好用的抓包工具,本文根据平时抓包经验,对之前wireshark抓包的一些常见知识点进行了整理. 有不当之处,欢迎指正 1.SYN,FIN会消耗一个序号,单独的ACK不消耗序 ...

  6. Mac OS X上使用Wireshark抓包

    Wireshark针对UNIX Like系统的GUI发行版界面采用的是X Window(1987年更改X版本到X11).Mac OS X在Mountain Lion之后放弃X11,取而代之的是开源的X ...

  7. MAC Wireshark抓包IOS

    网络抓包是个基础技能,对于网络协议的掌握有一定的要求.iOS上实现网络抓包可以用Charles(针对http和https),tcpdump(快速分析网络包),和Wireshare.之前写过一篇介绍tc ...

  8. Wireshark抓包,带你快速入门

    前言 关于抓包我们平时使用的最多的可能就是Chrome浏览器自带的Network面板了(浏览器上F12就会弹出来).另外还有一大部分人使用Fiddler,Fiddler也是一款非常优秀的抓包工具.但是 ...

  9. Http实战之Wireshark抓包分析

    Http实战之Wireshark抓包分析 Http相关的文章网上一搜一大把,所以笔者这一系列的文章不会只陈述一些概念,更多的是通过实战(抓包+代码实现)的方式来跟大家讨论Http协议中的各种细节,帮助 ...

随机推荐

  1. 图表可视化seaborn风格和调色盘

    seaborn是基于matplotlib的python数据可视化库,提供更高层次的API封装,包括一些高级图表可视化等工具. 使用seaborn需要先安装改模块pip3 install seaborn ...

  2. Fortify Audit Workbench 笔记 Password Management: Password in Configuration File(明文存储密码)

    Password Management: Password in Configuration File(明文存储密码) Abstract 在配置文件中存储明文密码,可能会危及系统安全. Explana ...

  3. Day14_RabbitMQ及数据同步

    学于黑马和传智播客联合做的教学项目 感谢 黑马官网 传智播客官网 微信搜索"艺术行者",关注并回复关键词"乐优商城"获取视频和教程资料! b站在线视频 0.学习 ...

  4. Python异常及异常处理

    Python异常及异常处理: 当程序运行时,发生的错误称为异常 例: 0 不能作为除数:ZeroDivisionError 变量未定义:NameError 不同类型进行相加:TypeError 异常处 ...

  5. go项目dockerfile最佳实践

    1. 前言 2. 不需要cgo情况下的最佳实践 3. 依赖cgo情况下的最佳实践 1. 前言 这几天在构建golang编写的web项目中,关于dockerfile编写的一些总结 可能是单纯我比较菜(大 ...

  6. linux的文件系统管理(ext4-tune2fs-e2fsck-xfs文件系统)

    文件系统管理 文件系统是Linux系统存放文件的空间.文件系统的类型有很多种,CentOS支持多种文件系统,目前常用的是ext4和xfs文件系统.我们以ext4文件系统为例来说明对文件系统的管理. U ...

  7. 使用VMware虚拟机建立Ubuntu与主机win7的文件共享与传输

    1.要想在虚拟机与主机之间建立共享文件夹必须先安装VMware Tools.方法见https://www.cnblogs.com/lsc666js/p/13403919.html. 2.在VMware ...

  8. 笨办法学python3练习代码ex21.py

    def add(a, b): print(f"ADDING {a} + {b}") return (a + b) def subtract(a, b): #subtract :减去 ...

  9. K短路 学习笔记

    K短路,顾名思义,是让你求从$s$到$t$的第$k$短的路. 暴力当然不可取,那么我们有什么算法可以解决这个问题? -------------------------- 首先,我们要维护一个堆. st ...

  10. Java课堂总结

    通过重载函数,来实现对不同类型的参数运算.