InputStream中的read()方法
API上说,read方法在输入数据可用、检测到流末尾或者抛出异常前,此方法一直阻塞。
这个阻塞的意思就是说: 程序一直停在read()方法这里,等待数据。没有数据就不继续往下执行,至到得到数据。
read()方法是阻塞式方法,但是接受不到消息总不能让它一直阻塞,求神人指点如何打断这个read方法
public void test(InputStream in){
byte[] bs=new byte[1024];
while(true){
try {
int available=in.available();// 可读取多少字节内容
if(available==0){// 没有可读取内容则退出
break;
}else{// 读取内容并输出
in.read(bs,0,available);
System.out.print(new String(bs,0,available));
}
Thread.currentThread().sleep(200);// 睡眠一段时间
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Firstly, the guarantee is "without blocking for more input" rather than
"without blocking": a read may still
block waiting for I/O to complete — the
guarantee is merely that it won't have to wait
indefinitely for data to be
written. The result of this method should not
be used as a license to do I/O on
a thread that shouldn't be blocked.
做网络编程的人对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 {
1. 14. public static void main(String[] args) {
2. 15. try {
3. 16. SocketAddress address = new InetSocketAddress("192.168.9.155", 30001);
4. 17. // 启动监听端口 8001
5. 18. ServerSocket ss = new ServerSocket();
6. 19. ss.bind(address);
7. 20. // 接收请求
8. 21. Socket s = ss.accept();
9. 22. new Thread(new T(s)).start();
10. 23. } catch (Exception e) {
11. 24. e.printStackTrace();
12. 25. }
13. 26. }
27. }
28. class T implements Runnable {
1. 29. public void run() {
2. 30. try {
3. 31. System.out.println(socket.toString());
4. 32. socket.setKeepAlive(true);
5. 33. socket.setSoTimeout(5 * 1000);
6. 34. String _pattern = "yyyy-MM-dd HH:mm:ss";
7. 35. SimpleDateFormat format = new SimpleDateFormat(_pattern);
8. 36. while (true) {
9. 37. System.out.println("开始:" + format.format(new Date()));
10. 38. try {
11. 39. InputStream ips = socket.getInputStream();
12. 40. ByteArrayOutputStream bops = new ByteArrayOutputStream();
13. 41. int data = -1;
14. 42. while((data = ips.read()) != -1){
15. 43. System.out.println(data);
16. 44. bops.write(data);
17. 45. }
18. 46. System.out.println(Arrays.toString(bops.toByteArray()));
19. 47. }catch(SocketTimeoutException e){
20. 48. e.printStackTrace();
21. 49. }catch(SocketException e){
22. 50. e.printStackTrace();
23. 51. } catch (Exception e) {
24. 52. e.printStackTrace();
25. 53. }
26. 54. Thread.sleep(1000);
27. 55. System.out.println(socket.isBound()); // 是否邦定
28. 56. System.out.println(socket.isClosed()); // 是否关闭
29. 57. System.out.println(socket.isConnected()); // 是否连接
30. 58. System.out.println(socket.isInputShutdown()); // 是否关闭输入流
31. 59. System.out.println(socket.isOutputShutdown()); // 是否关闭输出流
32. 60. System.out.println("结束:" + format.format(new Date()));
33. 61. }
34. 62. } catch (Exception e) {
35. 63. e.printStackTrace();
36. 64. }
37. 65. }
38. 66. private Socket socket = null;
39. 67. public T(Socket socket) {
40. 68. this.socket = socket;
41. 69. }
42. 70. public Socket getSocket() {
43. 71. return socket;
44. 72. }
45. 73. public void setSocket(Socket socket) {
46. 74. this.socket = socket;
47. 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. 10. }
11. 11. } catch (Exception e) {
12. 12. e.printStackTrace();
13. 13. }
14. 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
1. 17. at java.net.SocketInputStream.socketRead0(Native Method)
2. 18. at java.net.SocketInputStream.read(Unknown Source)
3. 19. at java.net.SocketInputStream.read(Unknown Source)
4. 20. at socket.T.run(SocketService.java:42)
5. 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. 10. }
11. 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
1. 13. at java.net.SocketInputStream.read(Unknown Source)
2. 14. at java.net.SocketInputStream.read(Unknown Source)
3. 15. at socket.T.run(SocketService.java:42)
4. 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
异常是不一样的,不一样的还有,如果是超时,则五秒钟循环一次,然后是连接中断,则不在循环马上再报错,因为连接已经挂了!但是打印这个连接还是有效的,这个我也不知道怎么回事!
所以,如果大家理解为超时时间内没有数据连接就自动关闭或失效,那么这个理解就非常有问题了!