And asynchronous operation results asynchronous channel

And asynchronous operation results asynchronous channel

The following reference Sunweiqin wrote "Java Network Programming core technology explain" a book of Chapter 12.
Source code download address is: http://lesson.javathinker.net/javanet/javanetsourcecode.rar

JDK7 beginning from the introduction of the asynchronous channel represents AsynchronousServerSocketChannel AsynchronousSocketChannel classes and classes, and the role of these two classes and classes SocketChannel ServerSocketChannel similar, except that the methods of the asynchronous channel is always non-blocking mode of operation, and their method of nonblocking Future object returns an immediate, asynchronous operation used to store results of the method.

AsynchronousSocketChannel class has the following non-blocking methods:

  • Future <Void> connect (SocketAddress remote): connect to a remote host.
  • Future <Integer> read (ByteBuffer dst): read data from the channel, is stored in a ByteBuffer. Future object contains the number of bytes actually read from the channel.
  • Future <Integer> write (ByteBuffer src): write data into the channel in ByteBuffer. Future object contains the number of bytes actually written to the channel.
  • AsynchronousServerSocketChannel class has the following non-blocking methods:

  • Future <AsynchronousSocketChannel> accept (): accepting client connection request. Future object contains AsynchronousSocketChannel objects created after the connection is established.

Using the asynchronous channel, the program can be executed in parallel a plurality of asynchronous operation, for example:

SocketAddress socketAddress=……;
AsynchronousSocketChannel client= AsynchronousSocketChannel.open();
//请求建立连接
Future<Void > connected=client.connect(socketAddress);
ByteBuffer byteBuffer=ByteBuffer.allocate(128);

//执行其他操作
//……

//等待连接完成
connected.get();  
//读取数据
Future<Integer> future=client.read(byteBuffer);

//执行其他操作
//……

//等待从通道读取数据完成
future.get();

byteBuffer.flip();
WritableByteChannel out=Channels.newChannel(System.out);
out.write(byteBuffer);

The following PingClient class demonstrates the use of asynchronous channels. It is constantly receiving a domain name (the name that is on the network host) entered by the user, and then establish a connection to port 80 on the host computer, connected to the time it takes to build the final print. If the program can not connect to the specified host, on print-related error messages. If the user enters "bye", ends the program. The following information is input by the user operating PingClient class information, and program output. Wherein the non-italic font row information indicating the user input to the console, italics font indicates the output line of the program:

C: \ the Chapter04 \ classes> the Java nonblock.PingClient
www.abc888.com
www.javathinker.net
connection fails: www.abc888.com result ping
results of ping www.javathinker.net: 20ms
BYE

The results can be seen from the above printing, PingClient connection with the remote host www.javathinker.net 20ms, www.abc888.com connected to host fails. Can also be seen from the results of the printing, the PingClient asynchronous communication mode, when the user enters a host name, without waiting for the processing result output program host name, can continue to input the next host name. Processing results from each hostname to wait until after the connection has succeeded or failed printed.

/* PingClient.java */
package nonblock;
import java.net.*;
……
class PingResult {  //表示连接一个主机的结果
  InetSocketAddress address;
  long connectStart;  //开始连接时的时间
  long connectFinish = 0;  //连接成功时的时间
  String failure;
  Future<Void> connectResult;  //连接操作的异步运算结果
  AsynchronousSocketChannel socketChannel;
  String host;
  final String ERROR="连接失败";

  PingResult(String host) {
      try {
          this.host=host;
          address =
              new InetSocketAddress(InetAddress.getByName(host),80);
      } catch (IOException x) {
          failure = ERROR;
      }
  }  

  public void print() {  //打印连接一个主机的执行结果
      String result;
      if (connectFinish != 0)
          result = Long.toString(connectFinish - connectStart) + "ms";
      else if (failure != null)
          result = failure;
      else
          result = "Timed out";
      System.out.println("ping "+ host+"的结果" + " : " + result);
  }
}

public class PingClient{
  //存放所有PingResult结果的队列
  private LinkedList<PingResult> pingResults=
               new LinkedList<PingResult>();
  boolean shutdown=false;
  ExecutorService executorService;

  public PingClient()throws IOException{
    executorService= Executors.newFixedThreadPool(4);
    executorService.execute(new Printer());
    receivePingAddress();
  }

  public static void main(String args[])throws IOException{
    new PingClient();
  }

  /** 接收用户输入的主机地址,由线程池执行PingHandler任务 */  
  public void receivePingAddress(){
    try{
      BufferedReader localReader=new BufferedReader(
                    new InputStreamReader(System.in));
      String msg=null;
      //接收用户输入的主机地址
      while((msg=localReader.readLine())!=null){
        if(msg.equals("bye")){
          shutdown=true;
          executorService.shutdown();
          break;
        }
        executorService.execute(new PingHandler(msg));
      }
    }catch(IOException e){ }
  }

  /** 尝试连接特定主机,并且把运算结果加入到PingResults结果队列中 */
  public void addPingResult(PingResult pingResult) {
     AsynchronousSocketChannel socketChannel = null;
     try {
       socketChannel = AsynchronousSocketChannel.open();

       pingResult.socketChannel=socketChannel;
       pingResult.connectStart = System.currentTimeMillis();

       synchronized (pingResults) {
         //向pingResults队列中加入一个PingResult对象
         pingResults.add(pingResult);
         pingResults.notify();
       }

       Future<Void> connectResult=
           socketChannel.connect(pingResult.address);
       pingResult.connectResult = connectResult;
    }catch (Exception x) {
      if (socketChannel != null) {
        try {socketChannel.close();} catch (IOException e) {}
      }
      pingResult.failure = pingResult.ERROR;
    }
  }

  /** 打印PingResults结果队列中已经执行完毕的任务的结果 */
  public void printPingResults() {
    PingResult pingResult = null;
    while(!shutdown ){
      synchronized (pingResults) {
        while (!shutdown && pingResults.size() == 0 ){
          try{
            pingResults.wait(100);
          }catch(InterruptedException e){e.printStackTrace();}
        }

        if(shutdown  && pingResults.size() == 0 )break;
        pingResult=pingResults.getFirst();

        try{
          if(pingResult.connectResult!=null)
            pingResult.connectResult.get(500,TimeUnit.MILLISECONDS);
        }catch(Exception e){
            pingResult.failure= pingResult.ERROR;
        }

        if(pingResult.connectResult!=null
           && pingResult.connectResult.isDone()){

          pingResult.connectFinish = System.currentTimeMillis();
        }

        if(pingResult.connectResult!=null
           && pingResult.connectResult.isDone()
           || pingResult.failure!=null){

           pingResult.print();
           pingResults.removeFirst();
           try {
              pingResult.socketChannel.close();
            } catch (IOException e) { }
         }
      }
    }
  }

  /** 尝试连接特定主机,生成一个PingResult对象,
     把它加入到PingResults结果队列中 */
  public class PingHandler implements Runnable{
    String msg;
    public PingHandler(String msg){
        this.msg=msg;  
    }
    public void run(){
        if(!msg.equals("bye")){
          PingResult pingResult=new PingResult(msg);
          addPingResult(pingResult);
        }
    }
  }

  /** 打印PingResults结果队列中已经执行完毕的任务的结果 */
  public class Printer implements Runnable{
    public void run(){
        printPingResults();
    }
  }
}

Results of the above PingResult class represents a connection host. PingClient class PingResults PingResult queue holds all objects.
PingClient class also defines two inner class represents a specific task:

  • PingHandler task categories: responsible to try to connect the client host address input via an asynchronous channel, and create a PingResult object that contains the asynchronous operation result of the connection operation. Then the object is added to PingResults PingResult result queue.
  • Printer task class: responsible for the results of the print job queue have been implemented in PingResults results. Print completed PingResult objects are removed from the PingResults queue.

PingClient main main thread class to do the following:

  • Create a thread pool.
  • Printer submit tasks to the thread pool.
  • Host address of the client continue to read input, submit PingHandler task to the thread pool. If the client input "bye", ends the program.

PingClient class thread pool to do the following:

  • Printer task execution.
  • PingHander perform the task.

Guess you like

Origin blog.51cto.com/sunweiqin/2452137