关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回

java.net.ConnectException:Connectiontimedoutwhenconnectingtoldap

发布时间:2022-07-27 13:54:13

背景

请求某ldap服务时候出错,错误如下:

ConnectionTimeout异常,telenet测试

telnet hostname 389

大概需要很久(约2分钟)才能通。
所以想的是设置请求的ConnectionTimeout值大一些试试

代码

增加超时配置

env.put("com.sun.jndi.ldap.connect.timeout", "10000");

来源:https://docs.oracle.com/javase/8/docs/technotes/guides/jndi/jndi-ldap.html

示例代码如下:

try
{
    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.PROVIDER_URL, "ldap://hostname:389");
    env.put(Context.SECURITY_CREDENTIALS, "simple");
    env.put("com.sun.jndi.ldap.connect.timeout", "10000");
    InitialLdapContext context = new InitialLdapContext(env, null);
} catch (NamingException e)
{
   
}

测试

  1. 超时值设置21秒内,确实会在指定的时间内抛出异常 (设置起作用了!)
  2. 超时值设置大于21秒,会在21秒左右的样子抛出异常 (设置没起作用?!)

这...

难道是源代码中间有处理吗?我们设置30秒超时,然后顺着new InitialLdapContext(env, null);这个方法一路跟下去,timeout的值一路传入到socket.connect()处,再往下就是调用native code了。
可以确定的是,异常抛出的ConnectionTimeout,绝对不是因为我们超了我们设置的超时而抛出的,而是一个内部的io异常导致的。

解决

检索相关关键词,在万能的Stackoverflow上发现同样的问题:https://stackoverflow.com/questions/14100806/java-net-connectexception-connection-timed-out-when-connecting-to-ldap
回答中两个人都提到是DNS解析问题,做法是:

  1. 使用nslookup hostname得到ip
  2. 确保这些ip的389端口都是通的

于是按照该方法试了下,多个ip中有一个是好的,修改代码中的ldap url为ldap://ip:389试了下,果然没有异常出现了。

那为啥Sockect connect timeout是21秒呢?

long start = System.currentTimeMillis();
try {
   Socket socket = new Socket();
   SocketAddress socketAddress = new InetSocketAddress("220.181.38.148", 389); //baidu ip
   socket.connect(socketAddress, 30*1000);
} catch (Exception e) {
   long end = System.currentTimeMillis();
   System.out.println(end-start);
   e.printStackTrace();
}

输出

21071
java.net.ConnectException: Connection timed out: connect
at java.base/java.net.PlainSocketImpl.connect0(Native Method)
at java.base/java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:101)
at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399)
at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242)
at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:224)
at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.base/java.net.Socket.connect(Socket.java:609)
at java.base/java.net.Socket.connect(Socket.java:558)

查了一下

Stackoverflow:
https://stackoverflow.com/questions/56146261/i-set-the-timeout-on-the-socket-and-i-found-that-this-value-cannot-be-greater-t
https://stackoverflow.com/questions/26896414/where-does-the-socket-timeout-of-21000-ms-come-from

.NET issue:
https://github.com/dotnet/runtime/issues/27232

OpenJDK:
https://bugs.openjdk.java.net/browse/JDK-7116990

可以说是语言无关的操作系统配置问题导致。

简单来说就是TCP建立连接的时候,服务端半天不给响应,那么第一次超时是3秒,第二次是6秒, 第三次是12秒...以此类推。
在Windows操作系统中,通过注册表SetTcpMaxConnectRetransmissions配置,默认是2。也就是会重试2次,3+6+12=21秒。

如果需要修改OS默认的配置,可参考
Linux: http://willbryant.net/overriding_the_default_linux_kernel_20_second_tcp_socket_connect_timeout
Windows: https://docs.microsoft.com/en-US/troubleshoot/windows-client/networking/tcpip-and-nbt-configuration-parameters


/template/Home/DawnNew/PC/Static

立即注册风纳云账号,免费体验多款产品

立即注册