Socket 之 5____阻塞和超时

一.  Socket 的I/O 调用可能会因为多种原因而阻塞。 数据输入方法 read(),  receive()  在没有数据可读时会阻塞, 也就是等待.  

Tcp 协议的 write()  在没有足够的空间缓存传输的数据时可能阻塞.

ServerSocket 的 accept()  和 Socket  的构造方法都会阻塞等待,  直到连接建立.

如果阻塞等待接收一个数据报文,而它已经丢失,则程序会无限期地阻塞下去. 

1.  accept(),  read()  和 receive()

对于这些方法,可以使用Socket, ServerSocket , DatagramSocket类的setSoTimeout()方法,设置基阻塞的最长时间,如果超过此时间,则抛出一个InterruptedIOException, 即 阴断  IO 异常. 对于Socket 实例,  在调用read()  方法前, 还可能使用Socket对象的InputStream 的 available()  来检查是否有可读的数据.


Socket()  无参构造方法返回一个没有建立连接的Socket实例,  需要连接时,调用该实例的connect(),  并指定一个远程终端和超时时间


2. write()  调用也会阻塞等待, 直到最后一个字节成功写入到 TCP 实现的本地缓存中。 如果可用的缓存空间比要写入的数据小, 在write()  调用返回前, 必须把一些数据成功传输到连接的另一端.  write()  方法的阻塞总时间最终还是取决于接收端的应用程序.


现在看一个实际示例:

 实现一个为每个客户端限定了服务时间的回显协议, 限定了一个时长TimeLimit,程序经过TimeLimit,  实现就自动终止.


import java.io.IOException;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

class TimelimitEchoProtocol implements Runnable {
  private static final int BUFSIZE = 32;  // Size (bytes) buffer
  private static final String TIMELIMIT = "10000";  // Default limit (ms)
  private static final String TIMELIMITPROP = "Timelimit";  // Thread property

  private static int timelimit;
  private Socket clntSock;
  private Logger logger;

  public TimelimitEchoProtocol(Socket clntSock, Logger logger) {
    this.clntSock = clntSock;
    this.logger = logger;
    // Get the time limit from the System properties or take the default
    timelimit = Integer.parseInt(System.getProperty(TIMELIMITPROP,TIMELIMIT));
  }

  public static void handleEchoClient(Socket clntSock, Logger logger) {

    try {
      // Get the input and output I/O streams from socket
      InputStream in = clntSock.getInputStream();
      OutputStream out = clntSock.getOutputStream();
      int recvMsgSize;                        // Size of received message
      int totalBytesEchoed = 0;               // Bytes received from client
      byte[] echoBuffer = new byte[BUFSIZE];  // Receive buffer
      long endTime = System.currentTimeMillis() + timelimit;
      int timeBoundMillis = timelimit;

      clntSock.setSoTimeout(timeBoundMillis);
      // Receive until client closes connection, indicated by -1
      while ((timeBoundMillis > 0) &&     // catch zero values
             ((recvMsgSize = in.read(echoBuffer)) != -1)) {
        out.write(echoBuffer, 0, recvMsgSize);
        totalBytesEchoed += recvMsgSize;
        timeBoundMillis = (int) (endTime - System.currentTimeMillis()) ;
        clntSock.setSoTimeout(timeBoundMillis);
      }
      logger.info("Client " + clntSock.getRemoteSocketAddress() +
		  ", echoed " + totalBytesEchoed + " bytes.");
    } catch (IOException ex) {
      logger.log(Level.WARNING, "Exception in echo protocol", ex);
    }
  }
  
  public void run() {
    handleEchoClient(this.clntSock, this.logger);
  }
}

Timelimit  EchoProtocol 类试图将回显连接的总服务时间限制在10 s内, 当 handleEchoClient()  被调用时,就通过当前时间和服务期限计算出服务的截止时间。  每次  read()  调用结束后将重新计算当前时间与截止时间的差值 ,  即剩余服务 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值