0%

Netty框架学习

Netty框架学习

Netty

Netty是一个异步的,基于事件模型驱动的网络应用框架。

1
TCP/IP -> 原生JDK BIO -> NIO -> Netty

BIO - Blocking IO

  • 类和接口都在 java.io 包中
  • 同步并阻塞
  • 一个连接一个线程
  • 基于流的方式处理数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package top.leezy.bio;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class BIOServer {
public static void main(String [] args) throws IOException {

ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();

ServerSocket serverSocket = new ServerSocket(15501);

System.out.println("Server start...");

while (true) {
System.out.println("Main thread : ID: " + Thread.currentThread().getId() + " Name: " + Thread.currentThread().getName());
// 监听客户端连接
final Socket socket = serverSocket.accept();
System.out.println("connected a client");
// 创建线程与之通讯
newCachedThreadPool.execute(() -> {
// 客户端通讯
handler(socket);
});
}
}

public static void handler(Socket socket) {
try {
// telnet 127.0.0.1 15501
System.out.println("Handler Thread info: ID: " + Thread.currentThread().getId() + " Name: " + Thread.currentThread().getName());
byte[] bytes = new byte[1024];
// 通过socket获取输入流
InputStream inputStream = socket.getInputStream();
// 循环读取客户端发送数据
while (true) {
int read = inputStream.read(bytes);
if (read != -1) {
// 输出读取数据
System.out.println(new String(bytes, 0, read));
} else {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("close connection...");
try {
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}

}

NIO - non-blocking IO

  • 类和接口都在 java.nio 包中
  • 同步非阻塞
  • 三大核心组件: Channel 通道, Buffer 缓冲区,Selector 选择器
  • 以块的方式处理数据

nio_structure

  1. 每个channel都会对应一个buffer
  2. selector 对应一个线程,一个selector监听多个channel
  3. 程序切换到哪个channel是由事件event决定的
  4. channel是双向的,可以返回底层操作系统的情况
  5. buffer是一个内存块,是一个数组,可以读也可以写,需要flip方法切换
Buffer

Buffer是一个顶层抽象父类,层级关系如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Buffer (java.nio)
IntBuffer (java.nio)
DirectIntBufferU (java.nio)
ByteBufferAsIntBufferL (java.nio)
DirectIntBufferS (java.nio)
ByteBufferAsIntBufferB (java.nio)
HeapIntBuffer (java.nio)
FloatBuffer (java.nio)
ByteBufferAsFloatBufferB (java.nio)
DirectFloatBufferU (java.nio)
ByteBufferAsFloatBufferL (java.nio)
DirectFloatBufferS (java.nio)
HeapFloatBuffer (java.nio)
CharBuffer (java.nio)
ByteBufferAsCharBufferL (java.nio)
DirectCharBufferS (java.nio)
StringCharBuffer (java.nio)
HeapCharBuffer (java.nio)
ByteBufferAsCharBufferB (java.nio)
DirectCharBufferU (java.nio)
DoubleBuffer (java.nio)
HeapDoubleBuffer (java.nio)
DirectDoubleBufferU (java.nio)
ByteBufferAsDoubleBufferB (java.nio)
DirectDoubleBufferS (java.nio)
ByteBufferAsDoubleBufferL (java.nio)
ShortBuffer (java.nio)
DirectShortBufferU (java.nio)
ByteBufferAsShortBufferL (java.nio)
ByteBufferAsShortBufferB (java.nio)
HeapShortBuffer (java.nio)
DirectShortBufferS (java.nio)
LongBuffer (java.nio)
HeapLongBuffer (java.nio)
ByteBufferAsLongBufferB (java.nio)
DirectLongBufferU (java.nio)
ByteBufferAsLongBufferL (java.nio)
DirectLongBufferS (java.nio)
ByteBuffer (java.nio)
HeapByteBuffer (java.nio)
MappedByteBuffer (java.nio)

Buffer类有四个属性:日常中主要使用的ByteBuffer

1
2
3
4
5
6
7
8
9
10
11
12
13
public abstract class Buffer {

// Invariants: mark <= position <= limit <= capacity
// 标记 flip后会变化
private int mark = -1;
// 位置索引,每次读写都会修改
private int position = 0;
// 缓存区当前可操作位置的极限,可以修改
private int limit;
// hb 数组容量
private int capacity;
}

Buffer支持 putget操作,put放什么进去,get就应该通过相应的数据类型取出来,否则会报BufferUnderflowException

Channel
  • BIO 中的 stream 是单向的,例如 FileInputStream 对象只能进行读取数据的操作,而 NIO 中的通道(Channel)是双向的,可以读操作,也可以写操作。
  • Channel在NIO中是一个接口
    1
    public interface Channel extends Closeable {}
  • 常用的Channel类有:
    FileChannel、DatagramChannel、ServerSocketChannel 和 SocketChannel。
Selector

netty的IO线程NioEventLoop汇聚了Selector选择器,可以做到一个单线程去管理多个通道,当该某个通道空闲时返回空,不会阻塞,而是去处理其他通道的数据。