java非阻塞nio例子

服务端时序图



HandleServer.java类

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.Date;
import java.util.Iterator;
import java.util.Set;

public class HandleServer implements Runnable{
	public Selector selector;
	public ServerSocketChannel servChanner;
	public volatile boolean stop;
	public HandleServer(int port) {
		try {
			//打开ServerSocketChannel,用于监听客户端的连接,是所有客户端的父连接
			servChanner=ServerSocketChannel.open();
			//设置为非阻塞
			servChanner.configureBlocking(false);
			//绑定监听端口
			servChanner.socket().bind(new InetSocketAddress(port), 1024);
			//创建打开多路复用器
			selector=Selector.open();
			//将客户端连接注册到多路复用器,并监听accept事件
			servChanner.register(selector, SelectionKey.OP_ACCEPT);
			System.out.println("The time server is start in port:"+port);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public void stop(){
		this.stop=true;
	}
	public void run(){
		//多路复用器在线程run方法的无限循环体内轮询准备就绪的Key
		while(!stop){
			try {
				//复用器等待1000毫秒
				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);
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if(selector!=null){
			try {
				selector.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	private void handleinput(SelectionKey key)throws IOException{
		//检查key是否有效
		if(key.isValid()){
			//判断这个key对应的channel是否已经准备好接收连接
			if(key.isAcceptable()){
				ServerSocketChannel ssc=(ServerSocketChannel)key.channel();
				//处理接收请求,完成tcp三次握手
				SocketChannel sc=ssc.accept();
				//将新接收的客户端连接注册到Reactor线程的多路复用器上,监听读操作
				sc.configureBlocking(false);
				sc.register(selector, SelectionKey.OP_READ);
			}
			//判断可读事件
			if(key.isReadable()){
				//获取读操作的通道
				SocketChannel sc=(SocketChannel)key.channel();
				//建立buffer缓存
				ByteBuffer readBuffer=ByteBuffer.allocate(1024);
				//通道开始往缓存读数据
				//n 有数据的时候返回读取到的字节数。
				//0 没有数据并且没有达到流的末端时返回0。
				//-1 当达到流末端的时候返回-1。
				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("this time server receive order:"+body);
					String currentTime="query time order".equalsIgnoreCase(body)
							?new Date(System.currentTimeMillis()).toString():"bad order";
					doWrite(sc,currentTime);
				}else if(readBytes<0){
					//小于零证明读写完了,关闭通道
					key.cancel();
					sc.close();
				}else{
					
				}
			}
		}
	}
	private void doWrite(SocketChannel channer,String response) throws IOException{
		if(response!=null && response.trim().length()>0){
			byte[] bytes=response.getBytes();
			ByteBuffer writeBuffer=ByteBuffer.allocate(bytes.length);
			writeBuffer.put(bytes);
			//注意此处的flip方法,是将当前位置设置为EOF,指针指向0,这样为客户端的读模式做好准备
			writeBuffer.flip();
			channer.write(writeBuffer);
		}
	}
	
}

以上是服务端代码,客户端代码如下:

                 


TimeClient.java类

public class TimeClient {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new Thread(new TimeClientHandle("127.0.0.1",8080),"client-001").start();
	}

}

TimeClientHandle.java类


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;

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){
		//设置ip和端口
		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) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public void run(){
		try {
			doConnect();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//轮询
		while(!stop){
			try {
				selector.select(1000);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			Set<SelectionKey> selectedKeys=selector.selectedKeys();
			Iterator<SelectionKey> it=selectedKeys.iterator();
			SelectionKey key=null;
			while(it.hasNext()){
				key=it.next();
				it.remove();
				try {
					//处理key
					handleinput(key);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		if(selector!=null){
			try {
				selector.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	private void handleinput(SelectionKey key)throws IOException{
		//查看key是否有效
		if(key.isValid()){
			//通过key获取有效的通道
			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=stop;
					}else if(readBytes<0){
						key.cancel();
						sc.close();
					}else{}
				}
			}
		}
	}
	
	private void doConnect() throws IOException{
		//ip,端口,异步连接服务器,判断是否成功
		if(socketChannel.connect(new InetSocketAddress(host, port))){
			//如果成功,直接注册读事件。
			socketChannel.register(selector, SelectionKey.OP_READ);
			//往服务端写数据
			dowrite(socketChannel);
		}else{
			//如果没有成功(即异步连接返回false,说明客户端已发送sync同步包,服务器没返回ack包,物理连接还没建立)
			socketChannel.register(selector, SelectionKey.OP_CONNECT);
		}
	}

	private void dowrite(SocketChannel sc)throws IOException{
		byte[] req="query time orderkkk".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");
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值