Java程序网络连接分析方法总结

1.  前言

相关内容如下:

Windows抓包与网络分析工具总结:https://blog.csdn.net/a82514921/article/details/104609924

Linux抓包与网络分析工具总结:https://blog.csdn.net/a82514921/article/details/104616502

Java程序网络连接分析方法总结:https://blog.csdn.net/a82514921/article/details/104616519

iptables模拟网络连接问题并分析:https://blog.csdn.net/a82514921/article/details/104616548

2.  Java

以下在Windows环境进行测试,使用的Java版本为JDK8。

2.1  BTrace

BTrace是Java平台的动态跟踪工具,下载地址为https://github.com/btraceio/btrace,使用说明可查看https://github.com/btraceio/btrace/wiki

以下使用的BTrace版本为1.3.11.3。

2.1.1  使用说明

2.1.1.1     下载BTrace

https://github.com/btraceio/btrace#installation说明了BTrace的下载地址,当前版本地址为https://github.com/btraceio/btrace/releases/tag/v1.3.11.3,可下载btrace-bin-1.3.11.3.tgz或btrace-bin-1.3.11.3.zip。

2.1.1.2     配置BTrace

将btrace-bin-xxx压缩包解压后即可使用,btrace的bin目录中包含了btrace、btracec、btracer等命令。

在Windows环境时,可将btrace的bin目录添加至环境变量的Path变量中,方便在任意目录执行btrace等命令。

2.1.1.3     BTrace动态附加到进程

通常情况下,将BTrace动态附加到程序,只需要执行“btrace [pid] [跟踪脚本文件名/路径]”。

可查看https://github.com/btraceio/btrace/wiki#dynamically-attaching-to-application说明。

用于快速连接到已运行的应用程序,获取感兴趣的数据并分离,删除任何跟踪代码。

将BTrace动态附加到程序的命令如下:

btrace [-p <port>] [-cp <classpath>] <pid> <btrace-script> [<args>]

l  port

BTrace agent监听的端口,是可选的参数。

l  classpath

设置BTrace编译期间搜索类的目录或jar文件命令,默认为“.”。

l  pid

需要被跟踪的Java程序的进程ID。

l  btrace-script

跟踪脚本文件名或路径。若为java文件,则会在使用前进行编译;否则会被当作预编译的class文件并使用。

2.1.1.4     通过BTrace启动Java程序

可查看https://github.com/btraceio/btrace/wiki#starting-application-with-btrace说明。

在这种模式下,BTrace会在应用程序启动代码运行之前就启动。可以在应用程序生命周期的早期跟踪执行的代码。

使用BTrace agent启动应用程序的语法如下:

java -javaagent:btrace-agent.jar=[<agent-arg>[,<agent-arg>]*]? <launch-args>

agent使用逗号分隔的参数列表,如下所示:

noServer - don't start the socket server

bootClassPath - boot classpath to be used

systemClassPath - system classpath to be used

debug - turns on verbose debug messages (true/false)

trusted - do not check for btrace restrictions violations (true/false)

dumpClasses - dump the transformed bytecode to files (true/false)

dumpDir - specifies the folder where the transformed classes will be dumped to

stdout - redirect the btrace output to stdout instead of writing it to an arbitrary file (true/false)

probeDescPath - the path to search for probe descriptor XMLs

startupRetransform - enable retransform of all the loaded classes at attach (true/false)

scriptdir - the path to a directory containing scripts to be run at the agent startup

scriptOutputFile - the path to a file the btrace agent will store its output

script - colon separated list of tracing scripts to be run at the agent startup

如果不需要自定义代理程序参数,则可以使用btracer应用程序脚本进行替代。

agent使用的参数格式可以参考https://github.com/btraceio/btrace/blob/master/docs/usersguide.html,示例如下:

java -javaagent:btrace-agent.jar=script=<pre-compiled-btrace-script> <MainClass> <AppArguments>

以下对下文会使用的agent参数进行说明:

l  debug

打印详细的调试日志(true开启)。

l  dumpClasses

将被修改类的字节码转储至文件(true开启)。

l  dumpDir

指定保存被修改类的字节码转储文件的保存目录。

l  stdout

将BTrace的输出重定向至标准输出,而不是保存至文件中(true重定向至标准输出)。

当stdout参数不是true时,BTrace的输出会保存至文件中,默认保存在class文件所在目录,文件名格式为“[类名].class-.default.[时间毫秒数].btrace”,如“TestSocketConnect.class-.default.1548128796288.btrace”。

输出文件相关参数配置有误时,可能在当前目录生成文件。

l  scriptdir

指定BTrace agent启动时需要执行的跟踪脚本的保存目录。

l  scriptOutputFile

指定BTrace agent将输出保存至文件的文件路径(需要指定文件路径,不能指定为目录)。

l  script

指定BTrace agent启动时需要执行的跟踪脚本的文件名或完整路径列表,使用冒号分隔。

需要执行的脚本需要提前使用btracec命令编译为字节码,即class文件。

当跟踪脚本文件保存在当前目录时,可通过script指定脚本文件名。

当通过scriptdir参数指定脚本文件目录时,可通过script指定脚本文件名。

其他情况下,可通过script指定脚本文件完整路径。

2.1.1.5     btracec命令

通常情况下,通过btracec命令将跟踪脚本由java文件编译为class文件,可执行“btracec [java文件名/路径]”,类似javac命令,生成的class文件在当前目录。

btracec命令使用说明见https://github.com/btraceio/btrace/wiki/btracec

btracec命令使用方法为:

btracec [-cp <classpath>] [-d <directory>] <one-or-more-BTrace-.java-files>

l  classpath

编译BTrace程序时用于编译的类路径,默认为“.”。

l  directory

保存编译生成的class文件的目录,默认为“.”。

2.1.1.6     BTrace脚本说明

BTrace脚本注解说明可查看https://github.com/btraceio/btrace/wiki/BTrace-Annotations,BTrace脚本的说明可查看https://github.com/btraceio/btrace/wiki/Trace-Scripts

以下介绍下文使用的注解。

@OnMethod注解,用于指定目录类,目标方法,及方法的位置。

@OnMethod注解的使用说明如下:

@OnMethod(clazz=<cname_spec>[, method=<mname_spec>]? [, type=<signature>]? [, location=<location_spec>]?)

 

cname_spec = <class_name> | +<class_name> | /regex/

class_name is a fully qualified class name

+class_name is a fully qualified class name prepended with +; means all subclasses and implementors of the prepended class name

/regex/ is a standard regular expression used to identify the class names

mname_spec = <method_name> | /regex/

method_name is a simple method name (no signature or return type)

signature = <return_type> ((arg_type(,arg_type)*)?

return_type is the methods return type as written in java (eg. void, java.lang.String)

arg_type is the argument type as written in java

当匹配方法到达指定位置时,将调用由此注解注释的操作方法。在OnMethod注解中,跟踪类名由“clazz”属性指定,跟踪方法由“method”属性指定。“clazz”可以是完全限定的类名(如java.awt.Component或在两个正斜杠中指定的正则表达式。请参考示例NewComponent.java和Classload.java。

正则表达式可以匹配零个或多个类,在这种情况下,所有匹配的类都会被检测。如“/java\.awt\..+/”匹配java.awt包中的所有类。此外,方法名称也可以是正则表达式,可匹配零个或多个方法。请参考示例MultiClass.java。

还有另一种方法可以抽象地指定跟踪类和方法。可以通过注解指定跟踪的类和方法。例如,将“clazz”属性指定为@javax.jws.WebService,则BTrace将检测由@WebService批解注释的所有类。类似地,方法级别注解可用于抽象地指定方法。请参考示例WebServiceTracker.java。

也可以将正则表达式与注解相结合 - 比如“@/com\.acme\..+/”匹配任何由与给定正则表达式匹配的注解注释的类。

可以通过指定超类型来匹配多个类。即匹配作为给定超类型的子类型的所有类。如“+java.lang.Runnable”匹配实现java.lang.Runnable接口的所有类。请参考示例SubtypeTracer.java。

2.1.1.7     BTrace脚本限制

BTrace脚本的限制可查看https://github.com/btraceio/btrace/wiki/Trace-Scripts#restrictions

经测试发现BTrace脚本中还存在以下限制:

不允许调用类的getClass()方法

不允许进行强制类型转换

若不满足以上限制,在使用btracec编译时,会出现类似“xxx.java:[行号]:method calls are not allowed - only calls to BTraceUtils are allowed”提示。

当需要调用类的getClass方法时,可以调用BTraceUtils的classOf方法获取Class对象,由于已经导入“import static com.sun.btrace.BTraceUtils.*;”,因此可以直接调用classOf方法。当需要获取Class的字符串类名时,可调用name方法。

由于无法进行强制类型转换,当需要将父类对象强制类型转换为子类对象并获取属性时,可以使用反射的方式。

BTraceUtils中的Reflective.field方法可以获取对象的field对象,可直接调用field方法。

BTraceUtils中的Reflective.get方法可以获取对象的field的值,可直接调用get方法。

BTraceUtils中的Reflective.printFields方法可以打印对象的全部field的值,可直接调用printFields方法。

BTrace提供的反射方法与JDK的反射方法使用类似。

2.1.1.8     BTrace脚本示例

BTrace脚本示例可从https://github.com/btraceio/btrace/tree/master/samples下载,各示例的说明可查看https://github.com/btraceio/btrace/blob/master/docs/usersguide.html

2.1.2  使用BTrace监控TCP连接

2.1.2.1     跟踪程序

Java程序在进行TCP连接时,通常需要调用java.net.Socket类的connect方法(BIO)。

以下使用btrace,当调用java.net.Socket类的connect方法时,在入口增加信息输出,用于监控TCP连接过程。

以下为btrace执行的TestSocketConnect.java类代码:

import com.sun.btrace.annotations.*;

  import static com.sun.btrace.BTraceUtils.*;

  import java.net.SocketAddress;

  

  @BTrace

  public class TestSocketConnect {

  

    @OnMethod(clazz = "java.net.Socket", method = "connect",

            location = @Location(value = Kind.ENTRY))

    public static void testFun(SocketAddress endpoint, int timeout) {

  

   println("Socket.connect " + name(classOf(endpoint)) + " " + endpoint);

        jstack();

        println("--------------------------------------------------------\r\n");

    }

}

在跟踪脚本的方法中添加被跟踪方法的调用参数,可以在跟踪脚本中获得被跟踪方法的参数值。

jstack方法可以打印调用堆栈。

2.1.2.2     执行跟踪程序

以下启动使用httpclient进行HTTP通信的Java程序进行测试,监控TCP连接操作。

在执行前,需要先使用btracec命令将java文件编译为class文件。

l  BTrace动态附加到进程

命令略。

由于以下进行测试时,Java程序只在测试时启动,不是长期启动,将BTrace动态附加到进程相对比较麻烦,每次需要修改Java程序的PID,因此通过BTrace启动Java程序测试更方便。

l  通过BTrace启动Java程序

使用IDEA执行Java程序,在“VM Options”中增加BTrace需要的参数,示例如下:

-javaagent:C:/dir/btrace/build/btrace-agent.jar=script=D:/dir/TestSocketConnect.class,stdout=true

上述参数中,设置为“stdout=true”,使BTrace输出到标准输出,如果需要输出到文件,可以去掉。

当需要查看BTrace详细调试信息时,可以增加“debug=true”参数。

可以将跟踪脚本的目录与文件名分开配置,如下所示:

-javaagent:C:/dir/btrace/build/btrace-agent.jar=scriptdir=D:/dir/,script=TestSocketConnect.class,stdout=true

添加以上参数后,正常启动,就可以通过BTrace启动被跟踪的Java程序。

2.1.2.3     跟踪结果

以下为BTrace的输出内容,可以看到TCP连接的服务器信息,及调用堆栈等(使用HTTP协议)。

Socket.connect java.net.InetSocketAddress /127.0.0.1:8888

java.net.Socket.connect(Socket.java)

org.apache.http.conn.socket.PlainConnectionSocketFactory.connectSocket(PlainConnectionSocketFactory.java:72)

org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:125)

org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:319)

org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:363)

org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:219)

org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195)

org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86)

org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)

org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)

org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)

org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106)

2.1.2.4     被改造的class分析

通过BTrace启动Java程序时,可以将被改造的类的字节码转储到文件。

在BTrace启动参数增加dumpClasses与dumpDir,修改为如下:

-javaagent:C:/dir/btrace/build/btrace-agent.jar=script=D:/dir/TestSocketConnect.class,stdout=true,dumpClasses=true,dumpDir=D:/dir1

执行后可以看到在dumpDir目录中生成了转存储的class文件,分别为TestSocketConnect_bcp.class与java\net\Socket.class。

TestSocketConnect_bcp.class文件忽略。

Socket.class是对JDK的Socket类进行了改造,反编译后查看内容如下:

public void connect(SocketAddress var1, int var2) throws IOException {

    $btrace$TestSocketConnect$testFun(var1, var2);
@OnMethod(

    clazz = "java.net.Socket",

    method = "connect",

    location = @Location(Kind.ENTRY)

)

  private static void $btrace$TestSocketConnect$testFun(SocketAddress var0, int var1) {

    if (BTraceRuntime.enter(TestSocketConnect.runtime)) {

        try {

            BTraceUtils.println("Socket.connect " + BTraceUtils.name(BTraceUtils.classOf(var0)) + " " + var0);

            BTraceUtils.jstack();

            BTraceUtils.println("--------------------------------------------------------\r\n");

            BTraceRuntime.leave();

        } catch (Throwable var2) {

            BTraceRuntime.handleException(var2);

            BTraceRuntime.leave();

        }

    }

}

可以看到,跟踪脚本对Socket类的connect方法进行了跟踪,在被改造的Socket类中,在connect方法入口增加了“$btrace$TestSocketConnect$testFun(var1, var2);”调用,在类的最后增加了“$btrace$TestSocketConnect$testFun(var1, var2);”方法的定义。

2.2  Arthas

Arthas是Alibaba开源的Java诊断工具,可参考https://alibaba.github.io/arthas/index.html

Arthas比BTrace功能更强大,使用更简单,只需要执行命令就可完成所需的操作。

以下使用Arthas 3.1.7版本。

2.2.1  使用Arthas监控TCP连接

java.net.Socket类属于系统级别的类,为了使Arthas对系统级别的类进行增强,需要将unsafe选项设置为true,可参考https://alibaba.github.io/arthas/options.html#options

在Arthas命令窗口中执行“options unsafe true”,开启对系统级别的类进行增强,输出结果如下所示:

[arthas@10152]$ options unsafe true

 NAME    BEFORE-VALUE  AFTER-VALUE

-----------------------------------

 unsafe  false         true

使用stack命令可以输出当前方法被调用的调用路径,可参考https://alibaba.github.io/arthas/stack.html

可使用stack命令监控TCP连接。

执行“stack java.net.Socket connect”,监控TCP连接时的调用堆栈,输出结果如下所示(使用HTTPS协议):

@java.net.Socket.connect()

at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:244)

at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:125)

at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:319)

at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:363)

at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:219)

at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195)

at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86)

at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)

at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)

at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)

at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106)

3.  网络分析工具使用场景

以上网络分析相关工具可在以下场景使用。

3.1  网络连接问题分析

当遇到网络连接问题时,可分析端口是否已监听,及监听端口的进程信息、IP地址信息等。(如监听时地址使用127.0.0.1,则只有本机能访问对应端口)。

3.2  分析通信数据

可以分析通信数据。

如在HTTP服务器捕获通信数据包,分析HTTP请求。

或捕获应用访问MySQL时的通信数据,分析是否使用了绑定变量方式,是否存在SQL注入风险。

3.3  分析HTTP keep-alive特性

可通过监控TCP连接操作,分析HTTP的keep-alive特性。

3.4  分析连接池

可通过监控TCP连接操作,分析连接池建立连接的情况。

3.5  监控连接数量

可以使用watch及ss命令,实时监控连接数量及状态。

3.6  监控连接信息

可以使用watch及对应命令(或使用lsof -r模式),实时监控关心的连接信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值