JAVA NIO知识点

版权声明:不短不长八字刚好@wzy https://blog.csdn.net/qq_38089964/article/details/84782901

NIO

java Non_blocking IO的学习

Knowledge points

  • Channel
  • Buffer
  • Selector

channel和buffer

从原来的面向数据字节流的模式改为现在面向通道的模式,一个通道可以指向一个输出流或者输出流, 而与程序直接接触的对象是buffer,也就是通道是我们操作的目标,buffer则是我们操作所用到的工具, 在程序中只需要读写buffer,然后将整个buffer送入通道或者从通道中整个取出。 在使用channel.read()或者write(),程序不会阻塞,继续往下执行,但是取出的数据就是真正目前获取的数据, 不能保证数据完全读入或者取出完毕。

Selector选择器

channel往selector里面注册事件(连接,读,写等),也就是告诉选择器,我对这些感兴趣; 在死循环里面调用selector.select(),这个是阻塞方法,当有通道可以读或者可以写或者可以连接, selector就会通知相应的channel可用,然后进行相应的操作。

Selector使用方式

  • Selector selector = Selector.open();新建一个选择器
  • SocketChannel socketChannel = SocketChannel.open(); socketChannel.configureBlocking(false); 打开一个客户端的chanel,并设置为非阻塞
  • socketChannel.register(selector, SelectionKey.OP_CONNECT);将这个channel注册到selector中,设置对连接事件感兴趣
  • 在一个死循环中调用selector.select();此方法为阻塞方法,也就是说当没有感兴趣的事件停下来等待,不会造成cpu空转
  • selector.selectedKeys();遍历selector的所有感兴趣事件
  • 如果某个事件是可用的(可读,可写,可连接的),那么client = ((SocketChannel) key.channel()); 通过这个SelectionKey来找到对应的通道,进行相应的操作(读、写、连接)

Selector的注销

由于Selector的注册是由位标志来记录的,也就是一个数的二进制的表示法,某个位上的值为一表示对某一个事件感兴趣, 那么注销就可以直接设置感兴趣的值为0,也就是所有的事件都不感兴趣,就将这个channel移出去,代表断开连接。

简单SocketServer的demo:

服务端:

package cn.wzy.socketDemo;


import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
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;

public class NIOServer {

	private int flag = 1;
	private Selector selector;
	private ByteBuffer inBuffer = ByteBuffer.allocate(1024);
	private ByteBuffer outBuffer = ByteBuffer.allocate(1024);
	private ServerSocket serverSocket;

	public NIOServer(int port) throws IOException {
		ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
		serverSocketChannel.configureBlocking(false);
		serverSocket = serverSocketChannel.socket();
		serverSocket.bind(new InetSocketAddress(port));
		selector = Selector.open();
		serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
		System.out.println("server start on " + port);
	}


	public void listen() throws IOException {
		while (true) {
			selector.select();
			Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
			while (iterator.hasNext()) {
				SelectionKey key = iterator.next();
				iterator.remove();
				handleKey(key);
			}
		}
	}

	private void handleKey(SelectionKey key) throws IOException {
		ServerSocketChannel server;
		SocketChannel client;
		int count;
		if (key.isAcceptable()) {
			System.out.println("收到连接");
			server = ((ServerSocketChannel) key.channel());
			client = server.accept();
			client.configureBlocking(false);
			client.register(selector,SelectionKey.OP_READ);
		} else if (key.isReadable()) {
			client = ((SocketChannel) key.channel());
			inBuffer.clear();
			try {
				count = client.read(inBuffer);
				if (count > 0) {
					System.out.print("收到数据:");
					System.out.println(new String(inBuffer.array(),0,count,"utf-8"));
					client.register(selector,SelectionKey.OP_WRITE);
				}
			} catch (Exception e) {
				System.out.println("客户端断开");
				client.register(selector,0);
			}
		} else if (key.isWritable()) {
			System.out.println("send successfully");
			client = ((SocketChannel) key.channel());
			outBuffer.clear();
			outBuffer.put(("some txt" + flag++).getBytes());
			outBuffer.flip();
			client.write(outBuffer);
			client.register(selector,SelectionKey.OP_READ);
		}
	}

	public static void main(String[] args) throws IOException {
		NIOServer nioServer = new NIOServer(7777);
		nioServer.listen();
	}
}

客户端:

package cn.wzy.socketDemo;

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 NIOClient {

	private static int flag = 1;
	private static ByteBuffer inBuffer = ByteBuffer.allocate(1024);
	private static ByteBuffer outBuffer = ByteBuffer.allocate(1024);
	private final static InetSocketAddress address = new InetSocketAddress("127.0.0.1", 7777);


	public static void main(String[] args) throws IOException {
		SocketChannel socketChannel = SocketChannel.open();
		socketChannel.configureBlocking(false);
		Selector selector = Selector.open();
		socketChannel.register(selector, SelectionKey.OP_CONNECT);
		socketChannel.connect(address);


		while (true) {
			selector.select();
			Set<SelectionKey> set = selector.selectedKeys();
			Iterator<SelectionKey> iterator = set.iterator();
			SocketChannel client;
			int count;
			while (iterator.hasNext()) {
				SelectionKey key = iterator.next();
				if (key.isConnectable()) {
					client = ((SocketChannel) key.channel());
					client.configureBlocking(false);
					if (client.isConnectionPending()) {
						client.finishConnect();
						outBuffer.clear();
						outBuffer.put("hello".getBytes());
						outBuffer.flip();
						client.write(outBuffer);
					}
					client.register(selector, SelectionKey.OP_READ);
				} else if (key.isReadable()) {
					client = ((SocketChannel) key.channel());
					inBuffer.clear();
					count = client.read(inBuffer);
					if (count > 0) {
						inBuffer.flip();
						System.out.println(new String(inBuffer.array(), 0, count, "utf-8"));
						client.register(selector, SelectionKey.OP_WRITE);
					}
				} else if (key.isWritable()) {
					client = ((SocketChannel) key.channel());
					outBuffer.clear();
					System.out.print("发送数据:");
					outBuffer.put(("send msg " + flag++).getBytes());
					outBuffer.flip();
					client.write(outBuffer);
					client.register(selector, SelectionKey.OP_READ);
				}
			}
			set.clear();
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_38089964/article/details/84782901
今日推荐