Wireshark抓包与常见问题解决
简介
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抓包与常见问题解决的更多相关文章
- 接口测试之——Charles抓包及常见问题解决(转载自https://www.jianshu.com/p/831c0114179f)
简介 Charles其实是一款代理服务器,通过成为电脑或者浏览器的代理,然后截取请求和请求结果达到分析抓包的目的.该软件是用Java写的,能够在Windows,Mac,Linux上使用,安装Charl ...
- Wireshark抓包分析/TCP/Http/Https及代理IP的识别
前言 坦白讲,没想好怎样的开头.辗转三年过去了.一切已经变化了许多,一切似乎从没有改变. 前段时间调研了一次代理相关的知识,简单整理一下分享之.如有错误,欢迎指正. 涉及 Proxy IP应用 原理/ ...
- Wireshark抓包工具使用教程以及常用抓包规则
转载:http://fangxin.blog.51cto.com/1125131/735178 Wireshark是一个非常好用的抓包工具,当我们遇到一些和网络相关的问题时,可以通过这个工具进行分析, ...
- TCP协议基础知识及wireshark抓包分析实战
TCP相关知识 应swoole长连接开发调研相关TCP知识并记录. 数据封包流程 如图,如果我需要发送一条数据给用户,实际的大小肯定是大于你发送的大小,在各个数据层都进行了数据的封包,以便你的数据能完 ...
- Wireshark抓包数据:理解与分析
wireshark是一个非常好用的抓包工具,本文根据平时抓包经验,对之前wireshark抓包的一些常见知识点进行了整理. 有不当之处,欢迎指正 1.SYN,FIN会消耗一个序号,单独的ACK不消耗序 ...
- Mac OS X上使用Wireshark抓包
Wireshark针对UNIX Like系统的GUI发行版界面采用的是X Window(1987年更改X版本到X11).Mac OS X在Mountain Lion之后放弃X11,取而代之的是开源的X ...
- MAC Wireshark抓包IOS
网络抓包是个基础技能,对于网络协议的掌握有一定的要求.iOS上实现网络抓包可以用Charles(针对http和https),tcpdump(快速分析网络包),和Wireshare.之前写过一篇介绍tc ...
- Wireshark抓包,带你快速入门
前言 关于抓包我们平时使用的最多的可能就是Chrome浏览器自带的Network面板了(浏览器上F12就会弹出来).另外还有一大部分人使用Fiddler,Fiddler也是一款非常优秀的抓包工具.但是 ...
- Http实战之Wireshark抓包分析
Http实战之Wireshark抓包分析 Http相关的文章网上一搜一大把,所以笔者这一系列的文章不会只陈述一些概念,更多的是通过实战(抓包+代码实现)的方式来跟大家讨论Http协议中的各种细节,帮助 ...
随机推荐
- 图表可视化seaborn风格和调色盘
seaborn是基于matplotlib的python数据可视化库,提供更高层次的API封装,包括一些高级图表可视化等工具. 使用seaborn需要先安装改模块pip3 install seaborn ...
- Fortify Audit Workbench 笔记 Password Management: Password in Configuration File(明文存储密码)
Password Management: Password in Configuration File(明文存储密码) Abstract 在配置文件中存储明文密码,可能会危及系统安全. Explana ...
- Day14_RabbitMQ及数据同步
学于黑马和传智播客联合做的教学项目 感谢 黑马官网 传智播客官网 微信搜索"艺术行者",关注并回复关键词"乐优商城"获取视频和教程资料! b站在线视频 0.学习 ...
- Python异常及异常处理
Python异常及异常处理: 当程序运行时,发生的错误称为异常 例: 0 不能作为除数:ZeroDivisionError 变量未定义:NameError 不同类型进行相加:TypeError 异常处 ...
- go项目dockerfile最佳实践
1. 前言 2. 不需要cgo情况下的最佳实践 3. 依赖cgo情况下的最佳实践 1. 前言 这几天在构建golang编写的web项目中,关于dockerfile编写的一些总结 可能是单纯我比较菜(大 ...
- linux的文件系统管理(ext4-tune2fs-e2fsck-xfs文件系统)
文件系统管理 文件系统是Linux系统存放文件的空间.文件系统的类型有很多种,CentOS支持多种文件系统,目前常用的是ext4和xfs文件系统.我们以ext4文件系统为例来说明对文件系统的管理. U ...
- 使用VMware虚拟机建立Ubuntu与主机win7的文件共享与传输
1.要想在虚拟机与主机之间建立共享文件夹必须先安装VMware Tools.方法见https://www.cnblogs.com/lsc666js/p/13403919.html. 2.在VMware ...
- 笨办法学python3练习代码ex21.py
def add(a, b): print(f"ADDING {a} + {b}") return (a + b) def subtract(a, b): #subtract :减去 ...
- K短路 学习笔记
K短路,顾名思义,是让你求从$s$到$t$的第$k$短的路. 暴力当然不可取,那么我们有什么算法可以解决这个问题? -------------------------- 首先,我们要维护一个堆. st ...
- Java课堂总结
通过重载函数,来实现对不同类型的参数运算.