1. Socket timeout
Java socket有如下两种timeout:
1.1 建立连接connect timeout

当不设置该参数时,指客户端要乞降做事端建立tcp连接时,会一贯壅塞直到连接建立成功,或抛非常。当设置了connectTimeout, 客户端要乞降做事端建立连接时,壅塞韶光超过connectTimeout时,就会抛出非常java.net.ConnectException: Connection timed out: connect。
我们看如下精简后的代码,首先是做事端:
做事端开启ServerSocket监听8080端口,再看客户端:
打印“Connected.”,修正客户端代码中的主机名为一个不存在的主机:
抛出非常:java.net.ConnectException: Connection timed out: connect,并打印:Connect failed, take time -> 18532ms. 也便是当未设置connect timeout时,connect方法会壅塞直到底层非常抛出。经由测试socket有个默认的超时时间,大概在20秒旁边(测试的值,不一定准确,待研究JVM源码)。下面我们来设置connect timeout,再看看效果:
抛出非常:java.net.SocketTimeoutException: connect timed out,并打印:Connect failed, take time -> 2014ms. 这里便是connect timeout发挥浸染了。
1.2 读取数据so timeout
先看下jdk源码注释:
Enable/disable SO_TIMEOUT with the specified timeout, in milliseconds. With this option set to a non-zero timeout, a read() call on the InputStream associated with this Socket will block for only this amount of time. If the timeout expires, a java.net.SocketTimeoutException is raised, though the Socket is still valid. The option must be enabled prior to entering the blocking operation to have effect. The timeout must be > 0. A timeout of zero is interpreted as an infinite timeout.
这个参数通过socket.setSoTimeout(int timeout)方法设置,可以看出它的意思是,socket关联的InputStream的read()方法会壅塞,直到超过设置的so timeout,就会抛出SocketTimeoutException。当不设置这个参数时,默认值为无穷大,即InputStream的read方法会一贯壅塞下去,除非连接断开。
下面通过代码来看下效果:
做事端代码:
做事端只接管socket但不发送任何数据给客户端。客户端代码:
客户端建立连接就开始读取InputStream。打印:
并且一贯壅塞在in.read(); 上。接下来我设置so timeout,代码如下:
抛出非常:java.net.SocketTimeoutException: Read timed out, 打印:read end, take -> 2000ms , 解释so timeout起浸染了。
1.3 小结
我们可以通过设置connect timeout来掌握连接建立的超时时间(不是绝对的,当设置的主机名不合法,比如我设置主机名为abc,会抛非常java.net.UnknownHostException: abc,但是此时connect timeout设置是不起浸染的,测试得出的结论,仅供参考)。
通过设置so timeout可以掌握流读取数据的超时时间。
2. 利用案例
2.1 MySQL jdbc timeout
查阅MySQL Connector/J 5.1 Developer Guide 中的jdbc配置参数,有
这两个参数分别便是对应上面我们剖析的connect timeout和so timeout。
参数的设置方法有两种,一种是通过url设置,
jdbc:mysql://[host1][:port1][,[host2][:port2]]...[/[database]] [?propertyName1=propertyValue1[&propertyName2=propertyValue2]...]即在url后面通过?加参数,比如jdbc:mysql://192.168.1.1:3306/test?connectTimeout=2000&socketTime=2000
还有一种办法是:
2.2 Jedis timeout
Jedis是最盛行的redis java客户端工具,redis.clients.jedis.Jedis工具的布局器中就有参数设置,
Jedis中so timeout个人以为是有比较主要意义的,首先jedis so timeout默认值为2000毫秒,jedis的操作流程是客户端发送命令给客户端实行,然后客户端就开始实行InputStream.read()读取相应,当某个命令比较耗时(比如数据非常多的情形下实行“keys ”),而导致客户端迟迟没有收到相应,就可能导致java.net.SocketTimeoutException: Read timed out非常抛出。一样平常是不建议客户端实行非常耗时的命令,但是也不用除有这种分外逻辑,那这时候就有可能须要修正Jeids中这个so timeout的值。
3. 总结
理解了这两个timeout之后,可以更好的处理一些网络做事的客户端和做事端,同时对排查一些问题也很有帮助。一样平常的成熟的网络做事和客户端都该当有这两个参数的配置方法,当利用碰着类似问题可以从这个方向去考虑下。