在Java中记录ConnectException时的源tcp端口?

在Java中记录ConnectException时的源tcp端口?,java,tcp,aop,aspectj,Java,Tcp,Aop,Aspectj,我正在调试Java应用程序(JDK1.8.0_65)抛出的奇怪连接拒绝错误 我有Wireshark捕获,但它包括正常和错误TCP段,我无法区分哪个是哪个 我想知道,当Java抛出ConnectException时,我是否可以使Java注销源端口号,以便使用它进行搜索。我可以使用AspectJ这样的工具来实现这一点吗 仅供参考,以下是堆栈跟踪: Caused by: java.net.ConnectException: Connection refused: connect

我正在调试Java应用程序(JDK1.8.0_65)抛出的奇怪连接拒绝错误

我有Wireshark捕获,但它包括正常和错误TCP段,我无法区分哪个是哪个

我想知道,当Java抛出
ConnectException
时,我是否可以使Java注销源端口号,以便使用它进行搜索。我可以使用AspectJ这样的工具来实现这一点吗

仅供参考,以下是堆栈跟踪:

Caused by: java.net.ConnectException: Connection refused: connect
                at java.net.DualStackPlainSocketImpl.connect0(Native Method) ~[na:1.8.0_65]
                at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79) ~[na:1.8.0_65]
                at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) ~[na:1.8.0_65]
                at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) ~[na:1.8.0_65]
                at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) ~[na:1.8.0_65]
                at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172) ~[na:1.8.0_65]
                at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) ~[na:1.8.0_65]
                at java.net.Socket.connect(Socket.java:589) ~[na:1.8.0_65]
...

如果客户端套接字是在没有显式的
bind()
的情况下创建的,则无法找到用于尝试建立连接的源端口。因此,为了能够报告源端口以进行调试,您需要在connect调用之前执行显式绑定。如果您有权访问客户端代码的源代码,则可以用类似的方式进行更新:

SocketAddress target = new InetSocketAddress(host, port);
int localPort = -1;
try (Socket socket = new Socket()) {
    socket.bind(null);
    localPort = socket.getLocalPort();
    socket.connect(target, timeout);
} catch (IOException e) {
    throw new IOException(
            String.format("couldn't connect to %s from port %d", target, localPort), e);
}
如果不能更改客户端源代码,可以使用以下方面来编写客户端代码。它的工作原理是拦截对套接字的方法调用。connect(…),确定套接字是否已绑定到端口,如果未绑定,将执行
绑定(null)
,该操作应找到要绑定的可用端口

import java.io.IOException;
import java.net.Socket;
import java.net.SocketAddress;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public aspect SocketExceptionLoggerAspect {

    private static final Logger logger = LoggerFactory
            .getLogger(SocketExceptionLoggerAspect.class);

    pointcut callToSocketConnect(SocketAddress target): 
        call(void Socket+.connect(..)) && args(target, ..);

    void around(SocketAddress target, Socket socket) : 
        callToSocketConnect(target) && target(socket) {

        int localPort = socket.getLocalPort();
        if (localPort == -1) {
            try {
                socket.bind(null);
                localPort = socket.getLocalPort();
            } catch (IOException e) {
            }
        }
        try {
            proceed(target, socket);
        } catch (IOException e) {
            logger.error(String.format("couldn't connect to %s from port %d", target,
                    localPort), e);
        }
    }
}
示例输出:
SocketExceptionLoggerAspect-无法从端口49840连接到stackoverflow.com/104.16.33.249:123

为什么?你需要源端口做什么?你不需要这些废话来找到一个可用的端口。只需绑定到端口0,然后从套接字获取本地套接字地址或本地端口,以查看操作系统分配了什么。@EJP您是对的。我根据您的建议更新了我的答案。我有一个问题:既然Socket在JDK中,那么类加载需要特别注意吗?这意味着您想使用AspectJ解决方案吗?它使用一个
call()
切入点,这意味着它只需要更改调用
Socket.connect()
的调用站点。如果这是您自己的源代码,那么在编译过程中或之后对其应用编织就足够了。如果是某种库代码,则需要编织库代码或使用加载时编织。如果是JDK代码,则只有加载时编织才能工作,您需要确保在JVM启动时启用LTW,以便在加载时编织所有调用
Socket.connect()
的代码。