注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

phperwuhan的博客

记载一个phper的历程!phperwuhan.blog.163.com

 
 
 

日志

 
 

客户端套接字(Socket)超时  

2010-03-05 13:41:14|  分类: php |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

来源:http://chenhua-1984.javaeye.com/blog/415078

客户端套接字的超时(timeout)就是指在客户端通过Socket和服务器进行通讯的过程中,由于网络延迟,网络阻塞等原因,造成服务器并未及时响应客户端的一种现象。在一段时间后,客户端由于未收到服务端的响应而抛出一个超时错误; 其中客户端所等待的时间就是超时时间。

 

由于生产超时错误的一端都是被动端;也就是说,这一端是在接收数据,而不是发送数据。对于客户端Socket来说,只有两个地方是在接收数据;一个是在连接服务器时;另一个是在连接服务器成功后,接收服务器发过来的数据时。因此,客户端超时也分为两种类型:连接超时和读取数据超时。

 

一、连接超时

 

这种超时在前面的例子中已经使用过。在Socket类中只有通过connect方法的第二个参数才能指定连接超时的时间。由于使用connect方法连接服务器必须要指定IP和端口;因此,无效的IP或端口将会引发连接超时错误。

 

二、读取数据超时

 

在连接服务器成功后,Socket所做的最重要的两件事就是“接收数据”和“发送数据”;而在接收数据时可能因为网络延迟、网络阻塞等原因,客户端一直处于等待状态;而客户端在等待一段时间后,如果服务器还没有发送数据到客户端,那么客户端Socket将会抛出一个超时错误。

 

我们可以通过Socket类的setSoTimeout方法来设置读取数据超时的时间;时间的单位是毫秒。这个方法必须在读取数据之前调用才会生效。如果将超时时间设为0,则不使用超时时间;也就是说,客户端什么时候和服务器断开,将完全取决于服务端程序的超时设置。如下面的语句将读取数据超时时间设为5秒。

Java代码 复制代码
  1. Socket socket = new Socket();   
  2. socket.setSoTimeout(5000);   
  3. socket.connect(… …);   
  4. socket.getInputStream().read();  
Socket socket = new Socket();  socket.setSoTimeout(5000);  socket.connect(… …);  socket.getInputStream().read();

 要注意的是不要将设置连接超时和读取数据超时设置得太小,如果值太小,如100,可能会造成服务器的数据还没来得及发过来,客户端就抛出超时错误的现象。下面的代码给出了一个用于测试连接超时和读取数据超时的例子。

Java代码 复制代码
  1. package mynet;   
  2.   
  3. import java.net.*;   
  4.   
  5. public class SocketTimeout   
  6. {   
  7.     public static void main(String[] args)   
  8.     {   
  9.         long time1 = 0, time2 = 0;   
  10.         Socket socket = new Socket();   
  11.         try  
  12.         {   
  13.             if (args.length < 4)   
  14.             {   
  15.                 System.out.println("参数错误!");   
  16.                 return;   
  17.             }   
  18.   
  19.             time1 = System.currentTimeMillis();   
  20.             socket.connect(new InetSocketAddress(args[0], Integer   
  21.                     .parseInt(args[1])), Integer.parseInt(args[2]));   
  22.             socket.setSoTimeout(Integer.parseInt(args[3]));   
  23.             time1 = System.currentTimeMillis();   
  24.             socket.getInputStream().read();   
  25.         }   
  26.         catch (SocketTimeoutException e)   
  27.         {   
  28.             if (!socket.isClosed() && socket.isConnected())   
  29.                 System.out.println("读取数据超时!");   
  30.             else  
  31.                 System.out.println("连接超时");   
  32.         }   
  33.         catch (Exception e)   
  34.         {   
  35.             System.out.println(e.getMessage());   
  36.         }   
  37.         finally  
  38.         {   
  39.             time2 = System.currentTimeMillis();   
  40.             System.out.println(time2 - time1);   
  41.         }   
  42.     }   
  43. }  
package mynet;    import java.net.*;    public class SocketTimeout  {      public static void main(String[] args)      {          long time1 = 0, time2 = 0;          Socket socket = new Socket();          try          {              if (args.length < 4)              {                  System.out.println("参数错误!");                  return;              }                time1 = System.currentTimeMillis();              socket.connect(new InetSocketAddress(args[0], Integer                      .parseInt(args[1])), Integer.parseInt(args[2]));              socket.setSoTimeout(Integer.parseInt(args[3]));              time1 = System.currentTimeMillis();              socket.getInputStream().read();          }          catch (SocketTimeoutException e)          {              if (!socket.isClosed() && socket.isConnected())                  System.out.println("读取数据超时!");              else                  System.out.println("连接超时");          }          catch (Exception e)          {              System.out.println(e.getMessage());          }          finally          {              time2 = System.currentTimeMillis();              System.out.println(time2 - time1);          }      }  }

 SocketTimeout类的main方法需要4个参数:IP(域名)、端口、连接超时、读取数据超时。下面让我们来用一组数据来测试这个例子。

测试1 :无效IP引发的超时错误

 

执行如下命令:

Java代码 复制代码
  1. java mynet.SocketTimeout 192.168.18.24 80 3000 5000  
java mynet.SocketTimeout 192.168.18.24 80 3000 5000

 运行结果:

Java代码 复制代码
  1. 连接超时   
  2. 3045  
连接超时  3045

 

注意:192.168.18.24是一个无效的IP;如果这个IP在网络环境中存在,请换其它的无效的IP.在这个测试用例中不能将无效的IP换成无效的域名;这是因为如果使用了域名来连接服务器,Java会先通过DNS将域名映射成相应的IP;如果这个域名是无效的,在映射的过程中就会出错;因此,程序也就不会执行连接服务器操作,自然也就不会抛出“连接超时”错误了。

 

测试2 :无效端口引发的超时错误

 

执行如下命令:

Java代码 复制代码
  1. java mynet.SocketTimeout  www.ptpress.com.cn 8888 3000 5000  
java mynet.SocketTimeout  www.ptpress.com.cn 8888 3000 5000

 运行结果:

Java代码 复制代码
  1. 连接超时   
  2. 3075  
连接超时  3075

 

Java代码 复制代码
  1. 测试3 :读取数据超时错误   
  2.   
  3. 执行如下命令: <SPAN id=zoom class=a14c><PRE>java mynet.SocketTimeout www.ptpress.com.cn 80 3000 5000</PRE>   
  4. </SPAN>  
测试3 :读取数据超时错误    执行如下命令: 
java mynet.SocketTimeout www.ptpress.com.cn 80 3000 5000

 运行结果:

Java代码 复制代码
  1. 读取数据超时!   
  2. 5008  
读取数据超时!  5008

 

测试4 :将读取数据超时设为0的效果

 

执行如下命令:

Java代码 复制代码
  1. java mynet.SocketTimeout www.ptpress.com.cn 80 3000 0  
java mynet.SocketTimeout www.ptpress.com.cn 80 3000 0

 运行结果:

Java代码 复制代码
  1. Connection reset   
  2. 131519  
Connection reset  131519

 

从前3个测试的输出结果不难看出,每个测试用例都将连接超时和读取数据超时分别设为3000和5000毫秒;而它们的运行结果并不是3000和5000毫秒,而是在所设定的超时时间的左右摇摆;这主要是因为系统所输出的时间并不都是超时时间;如有一些时间是Java处理错误、向控制台输出信息的时间。另外,由于系统计时的误差,也会影响到超时时间的准确性。但不管怎样,超时时间总会在所设定的时间周围摇摆。

 

对于测试4,将读取数据超时设为0后,SocketTimeout类经过了2分多钟(131519毫秒)才抛出Connection reset错误。这个抛出错误的时间和服务端程序的超时设置有关;也就是这个错误是由于服务端程序主动将客户端网络连接断开而产生的。

  评论这张
 
阅读(909)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017