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

Logging source tcp port when ConnectException in Java?

我正在调试从我的 Java 应用程序 (JDK 1.8.0_65) 抛出的一个奇怪的连接被拒绝错误。

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

我想知道是否可以让 Java 在它抛出 ConnectException 时注销源端口号,以便我可以使用它进行搜索。我可以使用像 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() 的情况下创建的,则无法找出用于尝试建立连接的源端口。因此,为了能够报告源端口以进行调试,您需要在连接调用之前进行显式绑定。如果您可以访问客户端代码的源代码,您可以用类似的方式更新它:

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);
}

如果无法更改客户端源代码,可以使用以下方面来编织客户端代码。它通过拦截对 Socket.connect(...) 的方法调用来工作,确定套接字是否已经绑定到端口,如果没有,将执行 bind(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 - couldn't connect to whosebug.com/104.16.33.249:123 from port 49840 <stack trace...>