socket setSoTimeout方法



做网络编程的人对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()  
setSoTimeout
public void setSoTimeout(int timeout)
	throws SocketException启用/禁用带有指定超时值的 SO_TIMEOUT,以毫秒为单位。将此选项设为非零的超时值时,在与此 Socket 关联的 InputStream 上调用 read() 将只阻塞此时间长度。
	如果超过超时值,将引发 java.net.SocketTimeoutException,虽然 Socket 仍旧有效。选项必须在进入阻塞操作前被启用才能生效。
	超时值必须是 > 0 的数。超时值为 0 被解释为无穷大超时值。 
参数:
timeout - 指定的以毫秒为单位的超时值。 
抛出: 
SocketException - 如果底层协议出现错误,例如 TCP 错误。
从以下版本开始: 
JDK 1.1 
另请参见:
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. }  
package socket;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class SocketService {
	public static void main(String[] args) {
		try {
			SocketAddress address = new InetSocketAddress("192.168.9.155", 30001);
			// 启动监听端口 8001
			ServerSocket ss = new ServerSocket();
			ss.bind(address);
			// 接收请求
			Socket s = ss.accept();
			new Thread(new T(s)).start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
class T implements Runnable {
	public void run() {
		try {
			System.out.println(socket.toString());
			socket.setKeepAlive(true);
			socket.setSoTimeout(5 * 1000);
			String _pattern = "yyyy-MM-dd HH:mm:ss";
			SimpleDateFormat format = new SimpleDateFormat(_pattern);
			while (true) {
				System.out.println("开始:" + format.format(new Date()));
				try {
					InputStream ips = socket.getInputStream();
					ByteArrayOutputStream bops = new ByteArrayOutputStream();
					int data = -1;
					while((data = ips.read()) != -1){
						System.out.println(data);
						bops.write(data);
					}
					System.out.println(Arrays.toString(bops.toByteArray()));
				}catch(SocketTimeoutException e){
					e.printStackTrace();
				}catch(SocketException e){
					e.printStackTrace();
				} catch (Exception e) {
					e.printStackTrace();
				}
				Thread.sleep(1000);
				System.out.println(socket.isBound()); // 是否邦定
				System.out.println(socket.isClosed()); // 是否关闭
				System.out.println(socket.isConnected()); // 是否连接
				System.out.println(socket.isInputShutdown()); // 是否关闭输入流
				System.out.println(socket.isOutputShutdown()); // 是否关闭输出流
				System.out.println("结束:" + format.format(new Date()));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	private Socket socket = null;
	public T(Socket socket) {
		this.socket = socket;
	}
	public Socket getSocket() {
		return socket;
	}
	public void setSocket(Socket socket) {
		this.socket = socket;
	}
}

 

 

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

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. }  
package socket;
import java.net.Socket;
public class Client {
	public static void main(String[] args) {
		try {
			Socket socket = new Socket("192.168.9.155", 30001);
			socket.setKeepAlive(true);
			while(true && null != socket){
				Thread.sleep(10 * 1000);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

 

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

 

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  
Socket[addr=/192.168.9.155,port=3017,localport=30001]
开始:2012-11-14 11:15:30
java.net.SocketTimeoutException: Read timed out
	at java.net.SocketInputStream.socketRead0(Native Method)
	at java.net.SocketInputStream.read(Unknown Source)
	at java.net.SocketInputStream.read(Unknown Source)
	at socket.T.run(SocketService.java:42)
	at java.lang.Thread.run(Unknown Source)
true
false
true
false
false
结束:2012-11-14 11:15:36
开始:2012-11-14 11:15:36
java.net.SocketTimeoutException: Read timed out
	at java.net.SocketInputStream.socketRead0(Native Method)
	at java.net.SocketInputStream.read(Unknown Source)
	at java.net.SocketInputStream.read(Unknown Source)
	at socket.T.run(SocketService.java:42)
	at java.lang.Thread.run(Unknown Source)
true
false
true
false
false
结束:2012-11-14 11:15:42
开始: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. }  
package socket;
import java.net.Socket;
public class Client {
	public static void main(String[] args) {
		try {
			Socket socket = new Socket("192.168.9.155", 30001);
			socket.setKeepAlive(true);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

 

打印如下:

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  
开始:2012-11-14 11:17:42
java.net.SocketException: Connection reset
	at java.net.SocketInputStream.read(Unknown Source)
	at java.net.SocketInputStream.read(Unknown Source)
	at socket.T.run(SocketService.java:42)
	at java.lang.Thread.run(Unknown Source)
true
false
true
false
false
java.net.SocketException: Connection reset
	at java.net.SocketInputStream.read(Unknown Source)
	at java.net.SocketInputStream.read(Unknown Source)
	at socket.T.run(SocketService.java:42)
	at java.lang.Thread.run(Unknown Source)
结束:2012-11-14 11:17:43
开始:2012-11-14 11:17:43
true
false
true
false
false
结束:2012-11-14 11:17:44

 

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

 

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

 

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

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

 


                               
评论
6 楼 fjjiaboming 2015-08-21  
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. }  
package socket;
import java.net.Socket;
public class Client {
	public static void main(String[] args) {
		try {
			Socket socket = new Socket("192.168.9.155", 30001);
			socket.setKeepAlive(true);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

你这哪里有关闭?
5 楼 crazysummer 2014-01-23  
博主,想问下,如果我的客户端用Socket短连接传输较大的数据,并且要从服务器端获得返回信息,那个这个超时的时间是不是要设置得比我这个数据的传输时间更大呢?
4 楼 xiaoZ5919 2012-11-15  
socket的读写是阻塞的,soTimeout是socket读写超时,而不是链接超时。
connection reset是由于在一个半关闭的connection上读取数据导致,client已经关闭但是server端没有关闭。http://xiaoz5919.iteye.com/blog/1685138
3 楼 cuisuqiang 2012-11-14  
huzhenyu 写道
直接拔网线需要使用心脏机制,A给B一个验证消息若A能正常收到回执消息,则证明A网络正常。

心跳包我尝试了,没用,网线掉后还能正常发送!但是一段时间后才会心跳异常!
2 楼 huzhenyu 2012-11-14  
直接拔网线需要使用心脏机制,A给B一个验证消息若A能正常收到回执消息,则证明A网络正常。
1 楼 cuisuqiang 2012-11-14  
还有一个问题,那就是如果是程序或网卡主动断连接,那能捕获连接中断的异常,但是如果是把网线的话就获得不了!
不知道这种情况下如何判定网络的中断!有知道的请发表一下!
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值