小编采访

水煮肉片,Netty学习 - 从TCP服务器到I/O模型,异乡人

学习Netty就不得不从TCP效劳器和I/O模型说起,了解TCP效劳器架构和I/O模型的演进有助于深化了解Netty。

TCP效劳器的架构

一般地,TCP效劳器有两种套接字,监听套接字和已衔接套接字。监听套接字用于TCP的监听,一旦衔接树立便发作已衔接套接字,效劳器运用已衔接套接字与客户端进行通讯。

  • 迭代效劳器
  • 在迭代效劳器中,监听套接字会一向堵塞直到能够承受衔接,承受水煮肉片,Netty学习 - 从TCP效劳器到I/O模型,异乡人衔接后运用已衔接套接字与客户端通讯,这些作业都是在同一个线程中完结的,暗示Java代码如下。这种与妻母共乐形式是串行处理,帮利冻顶乌龙茶很难应对并发量较大的状况。
try (ServerSocket serverSocket = new ServerSocket(port)) {
while (true) {
Socket socket = serverSocket.accept();
// ...
}
} catch (IOException e) {
e.printStackTrace();
}
  • 并发效劳器
  • 在并发效劳器中,监听套接字会一向堵塞直到能够承受衔接,承受衔接后,效劳器会让子线程/进程去处理已衔接套接字,暗示Java代码如下。这种形式虽然是并行处理,能够不搅扰效劳端的监听,可是由于每次新来一个恳求就会李名元发作一个新的线程去处理,出于资源的考虑很难应对高并发的状况。
try夏德仁去世 (ServerSocket serverSocket = new ServerSocket(port)) {
while (true) {
final Socket socket = serverSocket.accept();
new Thread(() -> {
/我的史前部落/ ...
}).start();
}
} catch (IOException e) {
e.printStackTrace();
}
  • IO多路复用(事情驱动)
  • 为了能在一个线程中处理多个衔接,能够运用IO多路复用(事情驱动),典型的有Linux C中的select、poll和epoll,Java的Selector类等。以Selector为例,调用者在选择器上为不同的衔接注册自己感兴趣的事情(可读/可写/可承受/可衔接),然后堵塞在select上,当事情发作时调用者便会得到告诉,而且知道是哪个衔接触发了事情,以便能够进一步处理。
  • Selector完结的HTTP效劳器暗示如下:
 public class NioServer {
private stati水煮肉片,Netty学习 - 从TCP效劳器到I/O模型,异乡人c final int BUFFER_SIZE = 512;
private static final String HTTP_RESPONSE_BODY = "Hello w水煮肉片,Netty学习 - 从TCP效劳器到I/O模型,异乡人olrd\n";
private static final 水煮肉片,Netty学习 - 从TCP效劳器到I/O模型,异乡人String HTTP_RESPONSE_HEADER = "HTTP/1.1 200\r\n" +
"Conte段蓓珊nt-Type: text/html\r\n" + "Content-Length: " + HTTP_RESPON除障者伽内什SE_BODY.length() + "\r\n\r\n";
private static final String HTTP_RESPONSE = HTTP_RESPONSE_HEADER + HTTP_RESPONSE_BODY;

// IO多路复用
pu梁焕臻blic void selector(红楼折钗记int port) {
try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
Selector selector = Selector.open()) {
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(port));
serverSocketChannel.register(selector,云泥沙 SelectionKey.OP_ACCEPT);
while (tr徐勤先ue) {
int readyChannels = selector.select();
if (readyChannels == 0) {
continue;
}
Set selectedKeys = selector.selectedKeys();
Iterator手机vpn免费 iter = selectedKeys.iterator();
while (iter.hasNext()) {
Se婴智贝佳lectionKey key = iter.next();
if (key.isAcceptable()) {
SocketChannel channel = ((ServerSocketChannel) key.channel()).accept();
System.out.println("accept: " + channel);
channel.configureBlocking水煮肉片,Netty学习 - 从TCP效劳器到I/O模型,异乡人(false);
channel.register(selector, SelectionKey.OP_READ);
}
if (key.isReadable()) {
SocketChannel channel = (SocketChannel) key.ch笑面死者现象annel();
System.out.println("read: " + channel);
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
int bytesRead = channel.read(buffer);
while (bytesRead > 0) {
buffer.flip();
while (buffer.hasRemaining()) {
System.out.print((char) b水煮肉片,Netty学习 - 从TCP效劳器到I/O模型,异乡人uffer.get());
}
buffer.clear();
bytesRead = channel.read(buffer);
}
ByteBuffer writeBuf = ByteBuffer.wrap(HTTP_RESPONSE.getBytes());
while (writeBuf.hasRemaining()) {
channel.write(writeBuf);
}
channel.close();
}
iter.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

I/O模型

一个输入操作一般包含两个不同的阶段[1][2]

  1. 等候数据准备好
  2. 从内核向进程仿制数据

(1) 堵塞式I/O模型

(2) 非堵塞式I/O模型

(3) I/O复用模型

(4) 信号驱动式I/O模型

(5) 异步I/O模型

同步I/O和异步I/O比照

POSIX把这两个术语界说如下:

  • 同步I/O操作导致恳求进程堵塞,直至I/O操作完结;
  • 异步I/O操作不导致恳求进程堵塞。

依据上述界说,前4种模型——堵塞式I/O模型、非堵塞式I/O模型、I/O复用模型和信号驱动式I/O模型都是世联职工自助渠道登录同步I/O模型,由于其间真实的I/伊兴阿O操作(recvfrom)将堵塞进程。只要异步I/O模型与POSIX界说的异步I/O相匹配。

Netty

Netty是一款异步的事情驱动的网络运用编程结构,支撑快速地开发可保护的高性能的面向协议的效劳器和客户端。与运用堵塞I/O来处理很多事情比较,运用非堵塞I/O来处理更快速、更经济,Netty运用了Reactor形式将事务和网络逻辑解耦,完结关注点别离[3]

Reactor形式

Reactor形式(反应堆形式)是一种处理一个或多个客户端并发交给效劳恳求的事情规划形式。当恳求抵达后,效劳处理程序运用I/O多路复用战略,然后同步地派发这些恳求至相关的恳求处理程序[4]

Reactor形式水煮肉片,Netty学习 - 从TCP效劳器到I/O模型,异乡人中的角重生之郡主宁汐色:

  • Reactor:监听端口,响应与分发事情;
  • Acceptor:当Accept事情到来时Reactor将Accept事情分发给Acceptor,Acceptor将已衔接套接字的通道注册到Reactor上;
  • Handler:已衔接套接字做事务处理。

单Reactor单线程

在这种形式中,Reactor、Accept美少女兵士凶恶漫画or和Handler都运行在一个线程中。

单Reactor多线程

在这种形式中,Reactor和Acceptor运行在同一个线程,而Handler只要在读和写阶段与Reactor和Acceptor运行在同一个线程,读写之间对数据的处理会被Reactor分发到线程池中。

多Reactor多线程

在这种形式中,主Reactor担任监听,与Acceptor运行在同一个线程,Acceptor会将已衔接套接字的通道注册到从Reac微信泡妞秘典tor上,从Reactor担任响应和分发事情,起到相似多线程Reactor的效果。Netty效劳端运用了该种形式。

推荐新闻