io


1.在jdk1.4,java引入了nio,nio是一种非阻塞io。


  1. 在nio中有三个概念
  • 缓冲区(buffer):java nio中数据的读取和存放需要通过缓冲区。

  • 通道(channel):可以理解为io中流的概念 ,与流不同的是,一个通道中既可以进行数据的读取,也可以进行数据的写入,而在io模型中,数据的读取和写入会有专门的输入和输出流来进行操作。

  • 选择器(select):通道可以在选择器上注册相关的事件,而选择器会有一个专门的线程来负责轮询这些事件,当某个写入事件或是读取事件可写或可读时,会交给相应的线程来处理。


  1. 通过java nio模拟一个服务端-客户端通信的实例
/**
* NIO Server服务
*/
class NIOServer{
// Selector->注册channel
Selector selector = null;
// ServerSocketChannel->服务端channel,类似ServerSocket
ServerSocketChannel serverSocketChannel;
// 处理selector轮询事件
private ChannelHandle handle;
// NIO服务关闭标识
private volatile boolean stop = false;

NIOServer(int port) {
try {
selector = Selector.open();
serverSocketChannel = ServerSocketChannel.open();
// 设置channel为非阻塞模式
serverSocketChannel.configureBlocking(false);
// 为channel绑定端口
serverSocketChannel.bind(new InetSocketAddress(port));
// 将channel注册到selector上,监听连接事件
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
handle = new ChannelHandle();
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 启动服务
* @throws IOException
*/
public void start() throws IOException {
while (!stop) {
// 获取到等待处理的IO事件数量
int readyChannels = selector.select();
// 若是等待处理的IO事件数量为0,不处理
if (readyChannels == 0) {
continue;
}
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
// 处理这些SelectionKey
while (iterator.hasNext()) {
// 获取到该key
SelectionKey key = iterator.next();
// 移除该key
iterator.remove();
// 分别处理各自事件
if (key.isAcceptable()) {
handle.handleAccept(key);
} else if (key.isReadable()) {
handle.handleRead(key);
} else if (key.isWritable()) {
handle.handleWrite(key);
}
}
}
}

// 停止该服务
public void stop() {
this.stop = true;
}
}


/**
* 针对selector上不同事件的处理类
*/
class ChannelHandle {
/**
* 处理连接事件
* @param key
* @throws IOException
*/
public void handleAccept(SelectionKey key) throws IOException {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
sc.register(key.selector(), SelectionKey.OP_READ);
}

/**
* 处理可读事件
* @param key
* @throws IOException
*/
public void handleRead(SelectionKey key) throws IOException {
SocketChannel sc = (SocketChannel) key.channel();
// fixme 对读取到的数据进行处理->相关协议解析
sc.register(key.selector(), SelectionKey.OP_WRITE);
}

/**
* 处理可写事件
* @param key
* @throws IOException
*/
public void handleWrite(SelectionKey key) throws IOException {
System.out.println("处理写数据");
// fixme 对输出结果按照相关协议进行封装
String header = "HTTP/1.1 200 OK\r\n";
StringBuffer result = new StringBuffer(header);
result.append("Content-Type:application/json\n");
result.append("\r\n");
result.append("hello,world");
SocketChannel channel = (SocketChannel)key.channel();
ByteBuffer wrap = ByteBuffer.wrap(result.toString().getBytes());
channel.write(wrap);
channel.close();
}
}

// 调用类
public class NIOUtil {
public static void main(String[] args) {
// 启动一个基于NIO的服务
NIOServer nioServer = new NIOServer(8070);
try {
nioServer.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
  1. 下面是通过java io的方式来实现的
public class IOUtil {

public static void main(String[] args) {
IOServer.createServer();
}
}


class IOServer {

private static volatile boolean stop = false;
/**
* 开启服务
*/
static void createServer() {
ExecutorService executorService =
Executors.newFixedThreadPool(3);
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(8090);
System.out.println("服务器在端口8090上启动。。。");
while (!stop) {
try {
Socket socket = serverSocket.accept();
// 将任务提交给线程池来处理
executorService.execute(new SocketHandle(socket));
} catch (Exception e) {
e.printStackTrace();
break;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (serverSocket != null) {
serverSocket.close();
}
executorService.shutdown();
} catch (IOException e) {
e.printStackTrace();
}
}
}

/**
* 关闭服务
*/
static void stopServer() {
stop = true;
}
}


/**
* socket处理线程类
*/
class SocketHandle implements Runnable {
private Socket socket;

SocketHandle(Socket socket) {
super();
this.socket = socket;
}

@Override
public void run() {
// 处理输入
InputStream is = null;
InputStreamReader isr = null;
BufferedReader br = null;
try {
is = socket.getInputStream();
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
String s = null;
while ((s = br.readLine()) != null && s.length() > 0) {
System.out.println(s);
s = null;
}
} catch (Exception e) {
e.printStackTrace();
} finally {

}
// 处理输出 \r\n 回车换行
OutputStream os = null;
try {
os = socket.getOutputStream();
os.write("HTTP/1.1 200 OK\r\n".getBytes());
os.write("Content-Type:application/json\n".getBytes());
os.write("\r\n".getBytes());
os.write("hello,world".getBytes());
os.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}