1、BIO代碼實例
服務端:
package BIODemo;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Created by L_kanglin on 2017/5/11.
*/
public class TimeServer {
public static void main(String[] args) throws IOException {
int port=9030;
if(args !=null && args.length >0){
port=Integer.valueOf(args[0]);
}
ServerSocket server=null;
try{
server= new ServerSocket(port);
System.out.println("The time server is start in port: "+port);
Socket socket=null;
while(true){
//當沒有客戶端連接時,程序會阻塞在accept這裏,當有客戶端訪問時,就會創建新的線程去重新執行。
socket=server.accept();
//每有一個客戶端訪問,就添加一個線程執行
new Thread(new TimeServerHandler(socket)).start();
}
}finally{
if(server !=null){
System.out.println("The time server close");
server.close();
server=null;
}
}
}
}
package BIODemo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
/**
* Created by L_kanglin on 2017/5/12.
*/
public class TimeServerHandler implements Runnable {
private Socket socket;
public TimeServerHandler(Socket socket) {
this.socket=socket;
}
@Override
public void run() {
BufferedReader in=null;
PrintWriter out=null;
try {
//獲取輸入流
in= new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
//構造輸出流
out= new PrintWriter(this.socket.getOutputStream(),true);
String currentTime=null;
String body=null;
Scanner sc= new Scanner(System.in);
while(true){
while(sc.hasNext()){
body=in.readLine();
if(body==null){break;}
System.out.println("server receive : "+body);
String str=sc.nextLine();
out.println(str);
// System.out.println("the server send: "+str);
}
/*currentTime="QUERY TIME ORDER".equalsIgnoreCase(body)?new java.util.Date
(System.currentTimeMillis()).toString():"BAD ORDER";
out.println(currentTime);*/
}
} catch(Exception e){
if(in != null){
try{
in.close();
}catch (IOException el) {
el.printStackTrace();
}
}
if(out !=null){
out.close();
out=null;
}
if(this.socket !=null){
try {
this.socket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
this.socket=null;
}
}
}
}
客戶端:
package BIODemo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.nio.Buffer;
/**
* Created by L_kanglin on 2017/5/12.
*/
public class TimeClient {
public static void main(String[] args) throws IOException {
int port = 9030;
if(args !=null && args.length>0){
port =Integer.valueOf(args[0]);
}
Socket socket = null;
BufferedReader in =null;
PrintWriter out=null;
while(true){
socket = new Socket("127.0.0.1",port);
in= new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(),true);
out.println("QUERY TIME ORDER"); //輸出給服務端
System.out.println("Send order 2 server succeed.");
String resp=in.readLine(); //獲取輸入流
System.out.println("NOW is: "+resp);
}
/*catch (Exception e) {
}finally{
//client自行依次關閉in、out和socket,否則會造成內存泄漏
if(out!=null){
out.close();
out=null;
}
if(in !=null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
in = null;
}
if(socket !=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
socket=null;
}
}*/
}
}
2、僞異步IO
服務端:
package BBIODemo;
import BIODemo.TimeServerHandler;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Created by L_kanglin on 2017/5/12.
* @description 首先創建一個時間服務器處理類的線程池,當接收到新的客戶端連接的時候,
* 將請求socket封裝成一個Task,然後調用線程池的execute方法執行,從而避免了每個請求接
* 入都創建一個新的線程。
*/
public class TimeServer {
public static void main(String[] args) throws IOException {
int port=9030;
if(args !=null && args.length >0){
port=Integer.valueOf(args[0]);
}
ServerSocket server=null;
try {
server = new ServerSocket(port);
System.out.println("The time server is start in port: "+port);
Socket socket = null;
TimeServerHandlerExecutePool singleExecutor = new TimeServerHandlerExecutePool
(50,10000); //創建IO任務線程池
while(true){
socket = server.accept();
//由於線程池和消息隊列都是有界的,因此,無論客戶端併發連接數多大,它都不會
//導致線程個數過於膨脹或者內存溢出,相比於傳統的一連接一線程模型,是一種改良
singleExecutor.execute(new TimeServerHandler(socket));
}
} finally{
if(server !=null){
System.out.println("The time server close");
server.close();
server=null;
}
}
}
}
package BBIODemo;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Created by L_kanglin on 2017/5/12.
*/
public class TimeServerHandlerExecutePool {
private ExecutorService executor;
public TimeServerHandlerExecutePool(int maxPoolSize,int queueSize){
executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors()
,maxPoolSize,120L,
TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(queueSize));
}
public void execute(Runnable task){
executor.execute(task);
}
}
客戶端:
package BBIODemo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
/**
* Created by L_kanglin on 2017/5/12.
* 客戶端通過socket創建,發送查詢時間服務器的“QUERY TIME ORDER”指令,然後
* 讀取服務端的響應並將結果打印出來,隨後關閉連接,釋放資源,程序退出執行。
*/
public class TimeClient {
public static void main(String[] args) throws IOException {
int port = 9030;
if(args !=null && args.length>0){
port =Integer.valueOf(args[0]);
}
Socket socket = null;
BufferedReader in =null;
PrintWriter out=null;
try{
socket = new Socket("127.0.0.1",port);
in= new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(),true);
out.println("QUERY TIME ORDER"); //輸出給服務端
System.out.println("Send order 2 server succeed.");
String resp=in.readLine(); //獲取輸入流
System.out.println("NOW is: "+resp);
} catch (Exception e) {
}finally{
if(out!=null){
out.close();
out=null;
}
if(in !=null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
in = null;
}
if(socket !=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
socket=null;
}
}
}
}
3、NIO代碼實例
服務端:
package NIODemo;
/**
* Created by L_kanglin on 2017/5/13.
*/
public class TimeServer {
public static void main(String[] args) {
int port=9030;
if (args !=null && args.length>0){
port=Integer.valueOf(args[0]);
}
MultiplexerTimeServer timeServer = new MultiplexerTimeServer(port);
//創建Reactor線程,並啓動線程
new Thread(timeServer,"NIO-MultiplexerTimerServer-001").start();
}
}
package NIODemo;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
/**
* Created by L_kanglin on 2017/5/13.
*/
public class MultiplexerTimeServer implements Runnable {
private Selector selector;
private ServerSocketChannel servChannel;
private volatile boolean stop;
//初始化多路複用器、綁定監聽端口
public MultiplexerTimeServer(int port){
try {
//創建多路複用器,並開啓
selector = Selector.open();
//打開ServerSocketChannel,用於監聽客戶端的連接,它是所有客戶端連接
//的父管道
servChannel = ServerSocketChannel.open();
//綁定監聽端口,設置連接爲非阻塞模式
servChannel.configureBlocking(false);
servChannel.socket().bind(new InetSocketAddress(port),1024);
//將ServerSocketChannel註冊到Reactor線程的多路複用器Selector上,
//監聽ACCEPT事件
servChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("The time server is start in port: "+port);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
public void stop(){
this.stop=true;
}
@Override
public void run() {
while(!stop){
try {
//多路複用器在線程run方法的無限循環體內輪詢準備就緒的Key
selector.select(1000);
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> it=selectionKeys.iterator();
SelectionKey key=null;
while(it.hasNext()){
key=it.next();
it.remove();
try{
handleInput(key);
}catch(Exception e){
if(key !=null){
key.cancel();
if(key.channel()!=null){
key.channel().close();
}
}
}
}
} catch (Throwable t) {
t.printStackTrace();
}
}
//多路複用器關閉後,所有註冊在上面的Channel和
// Pipe等資源都會被自動去註冊並關閉,所以不需
// 要重複釋放資源
if(selector !=null)
try{
selector.close();
}catch(IOException e){
e.printStackTrace();
}
}
private void handleInput(SelectionKey key) throws IOException {
if (key.isValid()){
//處理新接入的請求消息
ServerSocketChannel ssc= (ServerSocketChannel) key.channel();
//多路複用器監聽到有新的客戶端接入,處理新的接入請求,
//完成TCP三次握手,建立物理鏈路
SocketChannel sc= ssc.accept();
//設置客戶端鏈路爲非阻塞模式
sc.configureBlocking(false);
//將新接入的客戶端連接註冊到Reactor線程的多路複用器上,監聽讀操作,
//用來讀取客戶端發送的網絡消息
sc.register(selector,SelectionKey.OP_READ);
}
if(key.isReadable()){
//read the data
SocketChannel sc= (SocketChannel) key.channel();
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
//異步讀取客戶端請求消息到緩衝區
int readBytes = sc.read(readBuffer);
if(readBytes>0){
readBuffer.flip();
byte[] bytes=new byte[readBuffer.remaining()];
readBuffer.get(bytes);
String body=new String(bytes,"UTF-8");
System.out.println("the time server receive order: "+body);
String currentTime ="QUERY TIME ORDER".equalsIgnoreCase(body)? new java.
util.Date(System.currentTimeMillis()).toString():"BAD ORDER";
doWrite(sc,currentTime);
}else if(readBytes<0){
//對端鏈路關閉
key.cancel();
sc.close();
}else{
; //讀到0字節,忽略
}
}
}
private void doWrite(SocketChannel channel, String response) throws IOException {
if(response!=null && response.trim().length() >0){
byte[] bytes = response.getBytes();
ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
writeBuffer.put(bytes);
writeBuffer.flip();
channel.write(writeBuffer);
}
}
}
客戶端:
package NIODemo;
import BIODemo.TimeServerHandler;
import java.io.IOException;
/**
* Created by L_kanglin on 2017/5/15.
*/
public class TimeClient {
public static void main(String[] args) throws IOException {
int port = 9030;
if (args != null && args.length > 0) {
port = Integer.valueOf(args[0]);
}
new Thread(new TimeClientHandle("127.0.0.1",port),"TimeClient-001").start();
}
}
package NIODemo;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
/**
* Created by L_kanglin on 2017/5/15.
*/
public class TimeClientHandle implements Runnable {
private String host;
private int port;
private Selector selector;
private SocketChannel socketChannel;
private volatile boolean stop;
public TimeClientHandle(String host,int port){
this.host =host==null?"127.0.0.1":host;
this.port=port;
try {
selector=Selector.open();
socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
@Override
public void run() {
try {
doConnect();
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
while(!stop){
try {
selector.select(1000);
Set<SelectionKey> selectedkeys = selector.selectedKeys();
Iterator<SelectionKey> it =selectedkeys.iterator();
SelectionKey key=null;
while(it.hasNext()){
key =it.next();
it.remove();
handleInput(key);
if(key !=null){
key.cancel();
if(key.channel()!=null)
key.channel().close();
}
}
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
//多路複用器關閉後,所有註冊在上面的Channel和Pipe等資源都會被自動去
//註冊並關閉,所以不需要重複釋放資源
if(selector !=null){
try {
selector.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void handleInput(SelectionKey key) throws IOException {
if(key.isValid()){
//判斷是否連接成功
SocketChannel sc = (SocketChannel) key.channel();
if(key.isConnectable()){
if(sc.finishConnect()){
sc.register(selector,SelectionKey.OP_READ);
doWrite(sc);
}else{
System.exit(1); //連接失敗,進程退出
}
}
if(key.isReadable()){
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
int readBytes = sc.read(readBuffer);
if(readBytes>0){
readBuffer.flip();
byte[] bytes=new byte[readBuffer.remaining()];
readBuffer.get(bytes);
String body=new String(bytes,"UTF-8");
System.out.println("Now is : "+body);
this.stop=true;
}else if(readBytes<0){
//對端鏈路關閉
key.cancel();
sc.close();
}else{
; //讀到0字節,忽略
}
}
}
}
private void doConnect() throws IOException {
//如果直接連接成功,則註冊到多路複用器上,發送請求消息,讀應答
if(socketChannel.connect(new InetSocketAddress(host,port))){
socketChannel.register(selector, SelectionKey.OP_READ);
doWrite(socketChannel);
}else{
socketChannel.register(selector,SelectionKey.OP_CONNECT);
}
}
private void doWrite(SocketChannel sc) throws IOException {
byte[] req ="QUERY TIME ORDER".getBytes();
ByteBuffer writeBuffer=ByteBuffer.allocate(req.length);
writeBuffer.put(req);
writeBuffer.flip();
sc.write(writeBuffer);
if(!writeBuffer.hasRemaining())
System.out.println("Send order 2 server succeed.");
}
}