JavaRoadMap_9Java NIO

1. 为什么需要NIO?
使用传统的ServerSocket操作时会遇到accept()阻塞, BufferReader阻塞,以及大量的String垃圾,这是由于用来存储从BufferredReader中读入的String。同样问题在发送消息中也存在。传统的解决方法是使用线程池,即当服务器端监听到客户连接时,就为客户创建一个线程,并将该线程放入线程池中,在客户断开连接时,客户线程归还到线程池中。线程池使得服务器可以处理多个连接,但是同样带来开销,并且许多时间是浪费在阻塞的I/O上。


NIO的非阻塞I/O机制是围绕selector和channel来构建的。channel负责客户端和服务器端的通信,Selector是Channel的多路复用器。即Selector将传入的客户机请求分派到各自的请求处理程序中,比如连接事件,读取事件,写入事件。


2. NIO核心框架
-Buffer: 对比传统I/O不断浪费对象资源(String),NIO使用缓存区避免资源浪费。每一个非布尔型的基本类型都有一个缓存区。


-Charset:
通过CharsetEncoder和CharsetDecoder将CharBuffer转换成ByteBuffer.


-Channel:
替代数据流,提供读写Buffer的方式。


-Selector:
非阻塞I/O的核心,同时对多个SelectableChannel的I/O情况进行监控。


3. C/S with NIO

Class Server{
	main(){
		//创建selector
		Selector selector = Selector.open();
		//创建Socket
		ServerSocketChannel server = ServerSocketChannel.open();
		//启动端口监听
		InetSocketAddress ip = new InetSocketAddress(12345);
		server.socket().bind(ip);
		//注册selector
		server.configureBlocking(false);
		server.register(selector, SlectionKey.OP_ACCEPT);
		while(true){
			selector.select();
			Iterator<SelectionKey> it = selector.selectedKeys().iterator();
			while(it.hasNext()){
				SelectionKey key = it.next();
				it.remove();
				if(key.isAcceptable()){
				ServerSocketChannel server2 = (ServerSocketChannel)
				key.channel();
				SocketChannel channel = server2.accpet();
				channel.configureBlocking(false);
				channel.register(selector, SelectionKey.OP_READ);
				}else if(key.isReadable){
				Socketchannel channel = (SocketChannel)key.channel();
					
					//读数据
					CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
					ByteBuffer buffer = ByteBuffer.allocate(50);
					channel.read(buffer);
					buffer.flip();
					String msg = decoder.decode(buffer).toString();
					
					//写数据
					CharsetEncoder encoder = Charset.forName(“UTF-8”)
									.newEncoder();
					channel.write(encoder.encode(CharBuffer.wrap(msg)));
				}
			}
		}
	}
}


Class Client{
	main(){
		ClientThread client = new ClientThread();
		client.run();
		BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
		String readLine;
		while((readLine = sin.readLine())!=null){
			client.send(readLine);
		}
	}
}


Class ClientThread{
	CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
	CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();
	Selector selector = null;
	SocketChannel socket = null;
	SelectionKey clientKey = null;
	ClientThread(){
		selector = Selector.open();
		socket=SocketChannel.open();
		socket.configureBlocking(false);
		clientKey = socket.register(selector, SelectionKey.OP_CONNECT);
		InetSocketAddress ip = new InetSocketAddress("localhost",12345);
		socket.connect(ip);
	}
	
	run(){
		while(true){
			selector.select(1);
			Iterator<SelectionKey> it = selector.selectedKeys().iterator();
			while(it.hasNext()){
				SelectionKey key = it.next();
				it.remove();
				if(key.isConnectable()){
				SocketChannel channel = (SocketChannel)key.channel();
				channel.register(selector, SelectionKey.OP_READ);
				}else if(key.isReadable()){
				SocketChannel channel = (SocketChannel)key.channel();	
				ByteBuffer buffer = ByteBuffer.allocate(50);
				channel.read(buffer);
				buffer.flip();
				String msg = decoder.decode(buffer).toString();
			}
			
			}
		}
	}
	
	send(String msg){
		SocketChannel client = (SocketChannel)clientKey.channel();	
		client.write(encoder.encode(CharBuffer.wrap(msg)));
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值