JDK7 AIO (非阻塞IO)實現大併發TCPServer和TCPClient

NO IMAGE

JDK7 雖然已經發布了一段時間了,但是無奈,AIO相關介紹,尤其是靠譜兒的介紹實在是太少了。兄弟花了些時間,整理成冊,希望對learner有些幫助。

 

epoll成為Linux下開發大併發web 伺服器的首選已經好多年了,java世界裡,直到JDK 7的AIO出現才用上了這個feature。哎!不過亡羊補牢,為時未晚,下面就看下用AIO開發一個簡單的TCP Server和TCP Client。

 

1. 程式碼結構如下一共由6個檔案組成

JDK7 <wbr>AIO <wbr>(非阻塞IO)實現大併發TCPServer和TCPClient
2. Demo測試效果:

JDK7 <wbr>AIO <wbr>(非阻塞IO)實現大併發TCPServer和TCPClient

3. TCP Server 由三個檔案組成。

   AioTcpServer是主檔案

   AioAcceptHandler負責接收連線,採用遞迴模型

   AioReadHandler負責接收客戶端資料,仍然是非同步方式

3.1   AioTcpServer.java

package server;

import java.net.InetSocketAddress; 
import java.nio.channels.AsynchronousChannelGroup; 
import java.nio.channels.AsynchronousServerSocketChannel; 
import java.nio.channels.AsynchronousSocketChannel; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.Future; 
 
public class AioTcpServer implements Runnable { 
    private AsynchronousChannelGroup asyncChannelGroup;  
    private AsynchronousServerSocketChannel listener;  
  
    public AioTcpServer(int port) throws Exception { 
        ExecutorService executor = Executors.newFixedThreadPool(20); 
        asyncChannelGroup = AsynchronousChannelGroup.withThreadPool(executor); 
        listener = AsynchronousServerSocketChannel.open(asyncChannelGroup).bind(new InetSocketAddress(port)); 
    } 
 
    public void run() { 
        try { 
         
         AioAcceptHandler acceptHandler = new AioAcceptHandler();
            listener.accept(listener, new AioAcceptHandler());  
         Thread.sleep(400000); 
        } catch (Exception e) { 
            e.printStackTrace(); 
        } finally { 
         System.out.println(“finished server”);
        } 
    } 
 
    public static void main(String… args) throws Exception { 
        AioTcpServer server = new AioTcpServer(9008); 
        new Thread(server).start(); 
    } 
}

 

3.2   AioAcceptHandler.java

 

package server;

import java.io.IOException; 
import java.nio.ByteBuffer; 
import java.nio.channels.AsynchronousServerSocketChannel; 
import java.nio.channels.AsynchronousSocketChannel; 
import java.nio.channels.CompletionHandler; 
import java.util.concurrent.ExecutionException; 
import java.util.concurrent.Future; 
 
public class AioAcceptHandler implements CompletionHandler { 
    public void cancelled(AsynchronousServerSocketChannel attachment) { 
        System.out.println(“cancelled”); 
    } 
 
    public void completed(AsynchronousSocketChannel socket, AsynchronousServerSocketChannel attachment) { 
        try { 
         System.out.println(“AioAcceptHandler.completed called”);
            attachment.accept(attachment, this); 
            System.out.println(“有客戶端連線:” socket.getRemoteAddress().toString()); 
            startRead(socket); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } 
    } 
 
    public void failed(Throwable exc, AsynchronousServerSocketChannel attachment) { 
        exc.printStackTrace(); 
    } 
 
    public void startRead(AsynchronousSocketChannel socket) { 
        ByteBuffer clientBuffer = ByteBuffer.allocate(1024); 
        socket.read(clientBuffer, clientBuffer, new AioReadHandler(socket)); 
        try { 
            
        } catch (Exception e) { 
            e.printStackTrace(); 
        } 
    } 
}

 

3.3  AioReadHandler.java

 

package server;

import java.io.IOException; 
import java.nio.ByteBuffer; 
import java.nio.channels.AsynchronousSocketChannel; 
import java.nio.channels.CompletionHandler; 
import java.nio.charset.CharacterCodingException; 
import java.nio.charset.Charset; 
import java.nio.charset.CharsetDecoder; 
 
public class AioReadHandler implements CompletionHandler { 
    private AsynchronousSocketChannel socket; 
 
    public AioReadHandler(AsynchronousSocketChannel socket) { 
        this.socket = socket; 
    } 
 
    public void cancelled(ByteBuffer attachment) { 
        System.out.println(“cancelled”); 
    } 
 
    private CharsetDecoder decoder = Charset.forName(“GBK”).newDecoder(); 
 
    public void completed(Integer i, ByteBuffer buf) { 
        if (i > 0) { 
            buf.flip(); 
            try { 
                System.out.println(“收到” socket.getRemoteAddress().toString() “的訊息:” decoder.decode(buf)); 
                buf.compact(); 
            } catch (CharacterCodingException e) { 
                e.printStackTrace(); 
            } catch (IOException e) { 
                e.printStackTrace(); 
            } 
            socket.read(buf, buf, this); 
        } else if (i == -1) { 
            try { 
                System.out.println(“客戶端斷線:” socket.getRemoteAddress().toString());