Socket 关于设置Socket连接超时时间

做网络编程的人对setSoTimeout方法一定很熟悉,都知道是设置连接的超时时间!

但是我在网上找资料时发现很多人把这个超时时间理解成了链路的超时时间!我看了一下JDK 关于这个方法的说明,其实根本不是链路的超时时间!

 

Java代码   收藏代码
  1. setSoTimeout  
  2. public void setSoTimeout(int timeout)  
  3.     throws SocketException启用/禁用带有指定超时值的 SO_TIMEOUT,以毫秒为单位。将此选项设为非零的超时值时,在与此 Socket 关联的 InputStream 上调用 read() 将只阻塞此时间长度。  
  4.     如果超过超时值,将引发 java.net.SocketTimeoutException,虽然 Socket 仍旧有效。选项必须在进入阻塞操作前被启用才能生效。  
  5.     超时值必须是 > 0 的数。超时值为 0 被解释为无穷大超时值。   
  6. 参数:  
  7. timeout - 指定的以毫秒为单位的超时值。   
  8. 抛出:   
  9. SocketException - 如果底层协议出现错误,例如 TCP 错误。  
  10. 从以下版本开始:   
  11. JDK 1.1   
  12. 另请参见:  
  13. getSoTimeout()  

 

其实说白了他只是read方法的超时时间,这个方法是堵塞的!

 

写个小例子验证一下:

服务端,收到一个请求后处理,但是只处理一个请求,处理完毕后结束:

Java代码   收藏代码
  1. package socket;  
  2. import java.io.ByteArrayOutputStream;  
  3. import java.io.InputStream;  
  4. import java.net.InetSocketAddress;  
  5. import java.net.ServerSocket;  
  6. import java.net.Socket;  
  7. import java.net.SocketAddress;  
  8. import java.net.SocketException;  
  9. import java.net.SocketTimeoutException;  
  10. import java.text.SimpleDateFormat;  
  11. import java.util.Arrays;  
  12. import java.util.Date;  
  13. public class SocketService {  
  14.     public static void main(String[] args) {  
  15.         try {  
  16.             SocketAddress address = new InetSocketAddress("192.168.9.155"30001);  
  17.             // 启动监听端口 8001  
  18.             ServerSocket ss = new ServerSocket();  
  19.             ss.bind(address);  
  20.             // 接收请求  
  21.             Socket s = ss.accept();  
  22.             new Thread(new T(s)).start();  
  23.         } catch (Exception e) {  
  24.             e.printStackTrace();  
  25.         }  
  26.     }  
  27. }  
  28. class T implements Runnable {  
  29.     public void run() {  
  30.         try {  
  31.             System.out.println(socket.toString());  
  32.             socket.setKeepAlive(true);  
  33.             socket.setSoTimeout(5 * 1000);  
  34.             String _pattern = "yyyy-MM-dd HH:mm:ss";  
  35.             SimpleDateFormat format = new SimpleDateFormat(_pattern);  
  36.             while (true) {  
  37.                 System.out.println("开始:" + format.format(new Date()));  
  38.                 try {  
  39.                     InputStream ips = socket.getInputStream();  
  40.                     ByteArrayOutputStream bops = new ByteArrayOutputStream();  
  41.                     int data = -1;  
  42.                     while((data = ips.read()) != -1){  
  43.                         System.out.println(data);  
  44.                         bops.write(data);  
  45.                     }  
  46.                     System.out.println(Arrays.toString(bops.toByteArray()));  
  47.                 }catch(SocketTimeoutException e){  
  48.                     e.printStackTrace();  
  49.                 }catch(SocketException e){  
  50.                     e.printStackTrace();  
  51.                 } catch (Exception e) {  
  52.                     e.printStackTrace();  
  53.                 }  
  54.                 Thread.sleep(1000);  
  55.                 System.out.println(socket.isBound()); // 是否邦定  
  56.                 System.out.println(socket.isClosed()); // 是否关闭  
  57.                 System.out.println(socket.isConnected()); // 是否连接  
  58.                 System.out.println(socket.isInputShutdown()); // 是否关闭输入流  
  59.                 System.out.println(socket.isOutputShutdown()); // 是否关闭输出流  
  60.                 System.out.println("结束:" + format.format(new Date()));  
  61.             }  
  62.         } catch (Exception e) {  
  63.             e.printStackTrace();  
  64.         }  
  65.     }  
  66.     private Socket socket = null;  
  67.     public T(Socket socket) {  
  68.         this.socket = socket;  
  69.     }  
  70.     public Socket getSocket() {  
  71.         return socket;  
  72.     }  
  73.     public void setSocket(Socket socket) {  
  74.         this.socket = socket;  
  75.     }  
  76. }  

 

 

 第一个客户端,连接后一直保持连接对象的存活,但是不发送数据,服务端打印:

Java代码   收藏代码
  1. package socket;  
  2. import java.net.Socket;  
  3. public class Client {  
  4.     public static void main(String[] args) {  
  5.         try {  
  6.             Socket socket = new Socket("192.168.9.155"30001);  
  7.             socket.setKeepAlive(true);  
  8.             while(true && null != socket){  
  9.                 Thread.sleep(10 * 1000);  
  10.             }  
  11.         } catch (Exception e) {  
  12.             e.printStackTrace();  
  13.         }  
  14.     }  
  15. }  

 

打印如下,可以看到链路一直是活的,间隔超时时间的间隔就打印一组异常信息: 

 

Java代码   收藏代码
  1. Socket[addr=/192.168.9.155,port=3017,localport=30001]  
  2. 开始:2012-11-14 11:15:30  
  3. java.net.SocketTimeoutException: Read timed out  
  4.     at java.net.SocketInputStream.socketRead0(Native Method)  
  5.     at java.net.SocketInputStream.read(Unknown Source)  
  6.     at java.net.SocketInputStream.read(Unknown Source)  
  7.     at socket.T.run(SocketService.java:42)  
  8.     at java.lang.Thread.run(Unknown Source)  
  9. true  
  10. false  
  11. true  
  12. false  
  13. false  
  14. 结束:2012-11-14 11:15:36  
  15. 开始:2012-11-14 11:15:36  
  16. java.net.SocketTimeoutException: Read timed out  
  17.     at java.net.SocketInputStream.socketRead0(Native Method)  
  18.     at java.net.SocketInputStream.read(Unknown Source)  
  19.     at java.net.SocketInputStream.read(Unknown Source)  
  20.     at socket.T.run(SocketService.java:42)  
  21.     at java.lang.Thread.run(Unknown Source)  
  22. true  
  23. false  
  24. true  
  25. false  
  26. false  
  27. 结束:2012-11-14 11:15:42  
  28. 开始:2012-11-14 11:15:42  

  

 然后我们编写一个客户端,连接后马上关闭连接,也不发送任何数据:

Java代码   收藏代码
  1. package socket;  
  2. import java.net.Socket;  
  3. public class Client {  
  4.     public static void main(String[] args) {  
  5.         try {  
  6.             Socket socket = new Socket("192.168.9.155"30001);  
  7.             socket.setKeepAlive(true);  
  8.         } catch (Exception e) {  
  9.             e.printStackTrace();  
  10.         }  
  11.     }  
  12. }  

 

打印如下:

Java代码   收藏代码
  1. 开始:2012-11-14 11:17:42  
  2. java.net.SocketException: Connection reset  
  3.     at java.net.SocketInputStream.read(Unknown Source)  
  4.     at java.net.SocketInputStream.read(Unknown Source)  
  5.     at socket.T.run(SocketService.java:42)  
  6.     at java.lang.Thread.run(Unknown Source)  
  7. true  
  8. false  
  9. true  
  10. false  
  11. false  
  12. java.net.SocketException: Connection reset  
  13.     at java.net.SocketInputStream.read(Unknown Source)  
  14.     at java.net.SocketInputStream.read(Unknown Source)  
  15.     at socket.T.run(SocketService.java:42)  
  16.     at java.lang.Thread.run(Unknown Source)  
  17. 结束:2012-11-14 11:17:43  
  18. 开始:2012-11-14 11:17:43  
  19. true  
  20. false  
  21. true  
  22. false  
  23. false  
  24. 结束:2012-11-14 11:17:44  

 

异常是不一样的,不一样的还有,如果是超时,则五秒钟循环一次,然后是连接中断,则不在循环马上再报错,因为连接已经挂了!但是打印这个连接还是有效的,这个我也不知道怎么回事!

 

所以,如果大家理解为超时时间内没有数据连接就自动关闭或失效,那么这个理解就非常有问题了!

 

请您到ITEYE看我的原创:http://cuisuqiang.iteye.com

或支持我的个人博客,地址:http://www.javacui.com

你可能感兴趣的:(Socket 关于设置Socket连接超时时间)