在开发环境tomcat启动的过程中遇到了这样一个错误:
ERROR: transport error 202: bind failed: Address already in use
ERROR: JDWP Transport dt_socket failed to initialize, TRANSPORT_INIT(510)
JDWP exit error AGENT_ERROR_TRANSPORT_INIT(197): No transports initialized [debugInit.c:750]
看错误信息可以很明显地得出错误原因是端口占用,但是找遍了tomcat sever.conf中监听的端口,通过netstat -apn | grep port
命令查看,没有发现它们被占用。
随后通过进一步搜索关键词JDWP等可以得出是debug端口被占用了。那么,tomcat的debug模式是如何开启的呢?
JPDA(Java Platform Debugger Architecture) 是 Java 平台调试体系结构的缩写,它由三部分组成: Java 虚拟机工具接口(JVMTI),Java 调试线协议(JDWP)以及 Java 调试接口(JDI)。
详细的JPDA原理可以参看:深入JAVA调试体系
tomcat目录下使用以下命令可以在JPDA下开启debug:
bin/catalina.sh jpda start
在bin/catalina.sh文件中我们可以看到代码如下:
if [ "$1" = "jpda" ] ; then
if [ -z "$JPDA_TRANSPORT" ]; then
JPDA_TRANSPORT="dt_socket"
fi
if [ -z "$JPDA_ADDRESS" ]; then
JPDA_ADDRESS="8000"
fi
if [ -z "$JPDA_SUSPEND" ]; then
JPDA_SUSPEND="n"
fi
if [ -z "$JPDA_OPTS" ]; then
JPDA_OPTS="-agentlib:jdwp=transport=$JPDA_TRANSPORT,address=$JPDA_ADDRESS,server=y,suspend=$JPDA_SUSPEND"
fi
CATALINA_OPTS="$JPDA_OPTS $CATALINA_OPTS"
shift
fi
通过以上代码,我们可以发现,有三个参数可以对JPDA进行配置:
如果需要自定义JPDA,可以在catalina.sh中配置:
JPDA_TRANSPORT=dt_socket
JPDA_ADDRESS=5005
JPAD_SUSPEND=n
或者直接通过JPDA_OPTS参数进行配置:
JPDA_OPTS='-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
如果在catalina.sh中配置了以上这些参数,即使不通过jpda start命令启动tomcat,也会开启debug模式。
了解了tomcat中是如何开启debug的,那么上面遇到的端口占用问题,也就有了排查的思路。
我首先查看了catalina.sh文件,发现没有配置JPDA的参数,但是tomcat中配置环境变量的文件不止这一个,于是我使用grep搜索了bin目录:
[dev@dev-host tomcat]$ grep -lr JPDA bin
bin/catalina.bat
bin/catalina.sh
发现确实没有进行JPDA的配置,那么只有可能是通过jpda start默认开启了debug,于是在starup.sh文件末尾找到了这一句exec "$PRGDIR"/"$EXECUTABLE" jpda start "$@"
。而JDPA默认的传输端口8000确实是被另外的java进程占用了:
[dev@dev-host tomcat]$ netstat -apn | grep 8000
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
tcp 0 1 192.168.1.12:35874 100.100.25.95:8080 SYN_SENT 9285/java
那么,可以通过在catalina.sh中配置jpda端口为非8000端口解决该问题,或者直接去掉startup.sh中的jpda,以非debug模式启动tomcat。
案件到此侦破。