手机端小强原创文章,java小强个人博客站点
当前位置: 首页 >> 理论 >> Socket 关于设置Socket连接超时时间

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

91070 理论 | 2014-8-3

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

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

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方法的超时时间,这个方法是堵塞的!

 

写个小例子验证一下:

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

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;
 }
}

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

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();
  }
 }
}

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

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

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

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();
  }
 }
}

打印如下:

开始: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

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

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

推荐您阅读更多有关于“ tcp 超时 socket ”的文章

上一篇:协议 232转网口中的RealCom协议 下一篇:windows service2003 64位 配置使用PLSQL Developer

猜你喜欢

发表评论:

个人资料
blogger

java小强
没有思考,人生的路会越走越难!

搜索
分类
最新微语
  • 不是本人但真实经历,如果你得了绝症抑或大病,能告诉的人两只手能数过来,而能一直陪床真正帮你的人,一只手就够了。也许你会说我亲戚多哥们多同学多云云,但真遇上的时候,你敢说吗?即使你说了会有人像你想的那样吗?不要尝试考验人性,人走茶凉之类的话都听过,但不遇到事我们未曾理解其中的道理。

    2018-11-07 11:05

  • 每个人的一生都是不同的,我们都需要负重前行。每一种生活都是不同的,我们都需要真实面对。所经历的,让我学会一件事,顺其自然。人,总有很多自己想要的,总有很多困难要面对,总有很多人要去爱,我们不断思考人生,却总是迷失自己。如今,我们最缺的不是金钱和时间,而是忘记了自己的初衷。

    2018-09-28 14:42

  • 车也学了,年也过了,生日也过了,村里的会也赶了,这次,是真的,年过去了。不过我没回京,也没有在家找工作,我在等什么吗?反正现在正合了我这个懒人的要求,不过,我歇不住,思考下人生。

    2018-03-20 00:11

  • 8月1日,我已离开奋斗多年的北京。不知道是暂时的离开,还是永久的离别,反正已经离职在家,告别每日上班,每天苦累的煎熬,过一段属于自己的生活。以前是专职工作,现在专职生活。

    2017-08-18 12:47

  • 又弄完一个项目,累成狗,但是感觉又进步不少,除了很多坑已经踩过,做起来也是轻车熟路。同时也认识到,程序不在于你多牛逼,而是在乎你的细节把控度,而细节的关注,是一个优秀程序员必须要注意的。另外,要相信自己,勇敢向前,没人生下来就是成功的,而且,成功的路,比成功本身更重要。

    2017-06-30 09:46

  • 更多»

最新文章
热门文章
随机文章