Netty知识汇总
这篇主要是阅读Netty In Action这本书的一些有关Netty的知识点汇总
历史
阻塞io
一个线程用来处理一个连接,连接的创建和操作连接都是阻塞的
使用方法
try {
// 监听本地的8000端口
ServerSocket serverSocket = new ServerSocket(8000);
// 阻塞等待连接
Socket clientSocket = serverSocket.accept();
BufferedReader inputStream = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter writer = new PrintWriter(clientSocket.getOutputStream(), true);
String request;
// 阻塞等待输入
while((request = inputStream.readLine()) != null) {
if ("Done".equals(request)) {
break;
}
System.out.println(request);
}
} catch (IOException e) {
e.printStackTrace();
}
缺点
- 同时只能处理一个请求,如果需要处理多个请求,需要创建多个线程
- 大量的线程处于等待连接或者等待输入的状态,造成线程资源浪费
- 每个线程都的调用栈都需要分配内存,一方面物理机的内存限制了线程数量,另一方面,大量线程之间的线程切换带来大量开销
NIO
NIO使用一个Selector来管理多个Socket,每个Socket注册感兴趣的事件,通过事件通知的方式来确定哪些Socket可以进行处理
因此可以用一个线程来管理多个Socket
NIO有新旧两个版本,旧的版本是在jdk4中引入的,新的版本是在jdk7中引入的
使用
老的NIO
ServerSocketChannel serverChannel = ServerSocketChannel.open();
ServerSocket ss = serverChannel.socket();
InetSocketAddress address = new InetSocketAddress(8000);
ss.bind(address);
serverChannel.configureBlocking(false);
Selector selector = Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
try {
selector.select();
} catch (IOException ex) {
ex.printStackTrace();
// handle in a proper way
break;
}
Set readyKeys = selector.selectedKeys();
Iterator iterator = readyKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
iterator.remove();
try {
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel)
key.channel();
SocketChannel client = server.accept();
System.out.println("Accepted connection from " +
client);
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_WRITE
SelectionKey.OP_READ, ByteBuffer.allocate(100));
}
if (key.isReadable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer output = (ByteBuffer) key.attachment();
client.read(output);
}
if (key.isWritable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer output = (ByteBuffer) key.attachment();
output.flip();
client.write(output);
output.compact();
}
} catch (IOException ex) {
key.cancel();
try {
key.channel().close();
} catch (IOException cex) {
}
}
}
}
新的NIO
在新的NIO中引入了CompletionHandler,当操作完成时,对应的CompletionHandler会被调用
新的NIO相较老的NIO来说,最大的不同是通过使用CompletionHandler来注册回调,不需要检查当前哪些事件准备好了
当事件准备好了,对应的CompletionHandler会自动调用
public void nioTest() throws Exception{
final AsynchronousServerSocketChannel serverChannel =
AsynchronousServerSocketChannel.open();
InetSocketAddress address = new InetSocketAddress(8000);
serverChannel.bind(address);
final CountDownLatch latch = new CountDownLatch(1);
serverChannel.accept(null, new
CompletionHandler<AsynchronousSocketChannel, Object>() {
@Override
public void completed(final AsynchronousSocketChannel channel,
Object attachment) {
serverChannel.accept(null, this);
ByteBuffer buffer = ByteBuffer.allocate(100);
channel.read(buffer, buffer,