Giter Club home page Giter Club logo

java-nio-server's People

Watchers

 avatar

java-nio-server's Issues

Java-Nio-Server 结构解析

本篇文章基于 GitHub 上的开源项目 java-nio-server。 这个开源项目使用 Java 原生的 NIO API 来实现了一个很简单的 HTTP 服务器,此服务器在启动之后接收到任何 HTTP 请求消息,都只会返回对方一个带有 hello world 的网页。

0x01 线程模型

此服务器的基础架构如下所示。具体来说,有两个线程:AcceptorThread 和 ProcessorThread。

AcceptorThread 通过循环(注意,这里没有将 ServerSocketChannel 注册到 Selector 上)调用 ServerSocketChannel 的 accept 方法来判断是否有客户端要求建立连接。如果有的话,就将获取到的 SocketChannel 包装成 Socket 对象,然后存储到同步队列 socketQueue 中,这个同步队列在服务器中只存在一个。在 ProcessorThread 线程初始化时,会创建一个 ReadMessageBuffer 和 WriteMessageBuffer,以及 ReadSelector 和 WriterSelector。

然后在 ProcessorThread 线程执行时,会不断进行一个循环,这个循环执行三个操作:

  1. 首先是从 socketQueue 队列中获取到 Socket 连接,然后将 socket 注册到 readSelector 上面,监听 OP_READ 事件;
  2. 然后从调用 readSelector 的 selectNow 方法,如果某些 socket 连接有数据可以读,则从这个 socket 连接中不断读取 HTTP 消息,然后进行处理,在处理之后会把响应消息保存到 outboundMessageQueue 中
  3. 第三个操作是从 outboundMessageQueue 中读取响应消息,然后把响应消息写入到 socket 中返回给客户端。


0x02 内存模型

以上介绍了 NIO Server 的线程模型,对于一个 HTTP 服务器来说,还需要考虑如何接收消息,因为从客户端接收过来的消息有可能是部分的,有可能是多个 HTTP 消息,对于可能出现的这两种情况都需要进行处理。下面介绍 NIO Server 中内存模型。

对于每一个 Socket 连接,在其中初始化一个 MessageReader 和一个 MessageWriter,分别用来从 socket 读取消息以及往 socket 中写入消息。MessageReader 在读取消息时,可能只接收了部分消息,这个时候,应该在 MessageReader 内部设置一个缓冲区来暂时存储读取到的消息,等到后续的消息到来形成一个完整的 HTTP 报文,再进行处理。

但是假设每个 MessageReader 的缓冲区有 1MB(考虑可能出现较大的消息,所以设置为 1MB),由于每个 socket 连接中都有 MessageBuffer,当连接数较小时,还可以接受,当有 1000000 条连接时,需要 1TB 的内存。

所以,在实际设计内存模型时,在 NIO Server 初始化时,分别创建了一个 readMessageBuffer 和 writeMessageBuffer 对象。这个 readMessageBuffer 相当于 Server 中统一分配的内存池,任何一个 Socket#MessageReader 都会从 readMessageBuffer 中获取一块内存区域,用来保存接收到的 HTTP 消息。

对于 MessageWriter 也类似,在处理完请求消息之后,需要从 writeMessageBuffer 中获得一个内存块来保存生成的响应消息。因此,MessageWriter 和 MessageReader 内部并不自己设置一个内存区块,而是需要使用的话,就分别从 readMessageBuffer 和 writeMessageBuffer 中获得一个内存块,使用完毕之后就归还回去,NIO Server 会统一对内存进行管理。


如上图所示,在这个 NIO Server 中 MessageBuffer 是真正用来存储客户端发送过来的消息,它把发送过来的消息分为 small、medium 以及 large 三个层次,分别表示 4KB、128KB、1MB 大小。

  • small 类的消息分配了 1024 个 section
  • medium 类的消息分配了 128 个 section
  • large 类的消息分配了 16 个 section

在分配具体的消息块时,都是先分配一个 small 类型的 section 块,当接收到的消息字节数超过 CAPACITY_SMALL 时,就会分配一个新的 medium 类型的 section 块,然后将 small section 中的内容保存到 medium section 中,如果字节数超过 CAPACITY_MEDIUM 时,就会分配 large section 块,如果再超过,直接返回 false。

在分配每一类的 section 时,需要对已经分配出去的内存块进行记录。这里使用的是 QueueIntFlip 类来保存已经分配出去的 section 的起始地址。QueueIntFlip 内部有一个 int 数组 elements 来进行记录,这个 QueueIntFlip 使用类似于生产者消费者的模式。在其初始化时,就会填充满所有 section 的地址,当有 message 到达需要分配一个 section 进行存储时,就会从 QueueIntFlip 中 take 一个 freeBlock Address(消费者),当 message 处理完成之后,就调用 put 方法将其归还到 QueueIntFlip 中(生产者)。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.