java非阻塞nio例子

原创 2015年07月10日 15:23:28

服务端时序图



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");
		}
	}
}

JAVA非阻塞NIO_IO2

  • 2017年11月13日 13:56
  • 2.01MB
  • 下载

Java NIO——5 基于非阻塞编程NIO的例子

之前,写的大多都是一些NIO知识点,没有贴出实例,可能看起来比较晦涩,下面是一个基于非阻塞的nio实例 Server:...

Java NIO——6 基于非阻塞编程UDP NIO的例子

好吧,承接上篇文章,下面给出一个upd不可靠无连接的例子,他的次传送都是一个upd报文,不向上面文章中tcp是基于流的 代码:...

Java NIO——5 基于非阻塞编程NIO的例子

转自出处: 之前,写的大多都是一些NIO知识点,没有贴出实例,可能看起来比较晦涩,下面是一个基于非阻塞的nio实例 Server: [java...

Java NIO学习总结一(非阻塞特性)

NIO(New IO)是从Java 1.4版开始引入的新的IO API,其与标准的JAVA IO API的差异本质上体现在资源的利用方式上。可以从现实中餐厅排队的例子来理解这一点,饭点到了,某顾客选择...
  • c_craft
  • c_craft
  • 2015年12月29日 11:09
  • 840

JAVA NIO使用非阻塞模式实现高并发服务器

Java自1.4以后,加入了新IO特性,NIO. 号称new IO. NIO带来了non-blocking特性. 这篇文章主要讲的是如何使用NIO的网络新特性,来构建高性能非阻塞并发服务器. 文...

Java IO:面向缓冲区、同步、非阻塞式IO(NIO)

转载请注明出处:jiq•钦's technical Blog 引言JDK1.4中引入了NIO,即New IO,目的在于提高IO速度。特别注意JavaNIO不完全是非阻塞式IO(No-Blocking ...

Java网络编程——使用NIO实现非阻塞Socket通信

除了普通的Socket与ServerSocket实现的阻塞式通信外,java提供了非阻塞式通信的NIO API。先看一下NIO的实现原理。          从图中可以看出,服务器上所有Cha...

java NIO 实现非阻塞socket通信

java的nio为非阻塞式socket通信提供了如下几个类:           Selector : 它是SelectableChannel对象的多路复用器,所有希望采用非阻塞方式进行通信的c...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:java非阻塞nio例子
举报原因:
原因补充:

(最多只允许输入30个字)