BIO、NIO区别总结
BIO方式是java1.4之前支持的传统socket编程方式,socket.accept()会阻塞。在任何时间点,只有一个客户端能占用数据通道。如客户端有数据延迟,通道出现阻塞。
NIO:监听注册事件,客户端连接转换为事件,供服务端处理。
对于如下情况,BIO、NIO表现。
| 等待数据时间 | 服务端处理数据时间 |
Request1 | 10s | 1s |
Request2 | 1s | 2s |
- 多线程处理请求
BIO等待时间=10+1+2=13s
NIO等待时间=1+2+7+1=11s
- 单线程处理请求
BIO等待时间=10+1+1+2=14s
NIO等待时间=1+2+7+1=11s
BIO、NIO模拟http
- BIOServer
package tomcat;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
public class BioTomcat {
public static void sendResponse(Socket socket) throws IOException {
OutputStream outputStream = socket.getOutputStream();
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(outputStream));
String show = "<html><h1 style='color: green'> BIOServer!!!" + new Date().getSeconds() + "</h1>" +
"今天是2018年12月13日 星期四" +
"<html>" ;
out.write("HTTP/1.0 200 OK");
out.newLine();
//返回一个首部
out.write("Content-Type:text/html");
out.newLine();
out.write("Content-Length: " + show.length() );
out.newLine();
out.write("charset=gbk");
out.newLine();
// 根据 HTTP 协议, 空行将结束头信息
out.newLine();
// 输出请求资源
out.write(show);
out.newLine();
out.flush();
out.close();
}
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8088);
System.out.println("服务器启动:8088");
while (true){
Socket socket = server.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null && !line.isEmpty()){
System.out.println(line);
}
sendResponse(socket);
socket.close();
}
}
}
- NIOServer
package tomcat; import java.io.*; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.util.Date; import java.util.Iterator; import java.util.Set; public class NioTomcat { public static String getString(ByteBuffer buffer) { Charset charset = null; CharsetDecoder decoder = null; CharBuffer charBuffer = null; try { charset = Charset.forName("UTF-8"); decoder = charset.newDecoder(); charBuffer = decoder.decode(buffer.asReadOnlyBuffer()); return charBuffer.toString(); } catch (Exception ex) { ex.printStackTrace(); return ""; } } private static void listen(Selector selector) throws IOException { while (true){ int wait = selector.select(1000); if (wait == 0){ continue; } Set<SelectionKey> keys = selector.selectedKeys(); Iterator<SelectionKey> iterator = keys.iterator(); while (iterator.hasNext()){ SelectionKey key = iterator.next(); handle(key, selector); iterator.remove(); } } } public static void handle(SelectionKey key, Selector selector) throws IOException { if (key.isAcceptable()){ ServerSocketChannel server = (ServerSocketChannel)key.channel(); server.accept().configureBlocking(false).register(selector, SelectionKey.OP_READ); } else if (key.isReadable()){ SocketChannel socketChannel = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); socketChannel.read(buffer); buffer.flip(); System.out.println(getString(buffer)); socketChannel.register(selector, SelectionKey.OP_WRITE); } else if (key.isWritable()){ SocketChannel socketChannel = (SocketChannel) key.channel(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(byteArrayOutputStream)); String show = "<html><h1 style='color: green'> NIOServer!!!" + new Date().getSeconds() + "</h1>" + "今天是2018年12月13日 星期四" + "<html>" ; writer.write("HTTP/1.0 200 OK"); writer.newLine(); writer.write("Content-Type:text/html"); writer.newLine(); writer.write("Content-Length: " + show.length() ); writer.newLine(); writer.newLine(); writer.write(show); writer.flush(); writer.close(); socketChannel.write(ByteBuffer.wrap(byteArrayOutputStream.toByteArray())); socketChannel.close(); } } public static void main(String[] args) throws IOException { ServerSocketChannel server = ServerSocketChannel.open(); server.bind(new InetSocketAddress(8000)); server.configureBlocking(false); Selector selector = Selector.open(); server.register(selector, SelectionKey.OP_ACCEPT); System.out.println("服务器启动8000"); listen(selector); } }