Getty は、Java NIO を学ぶために私が作成した NIO フレームワークであり、実装プロセス中に Netty の設計を参照し、Groovy を使用して実装しました。単なるおもちゃですが、スズメは小さく、すべての内臓が備わっています。実装の過程で、NIO の使い方に慣れるだけでなく、Netty の設計アイデアを多く学び、コーディングと設計の能力も向上しました。 。
なぜ Groovy を使って書いているかというと、Groovy を学んだばかりで、練習のために使っただけだからです。また、Groovy は Java と互換性があるため、基本的な実装は依然として Java に基づいています。 Java API。
Getty のコア コード行は 500 行を超えません。一方で、Groovy の簡潔な構文の恩恵を受けていますが、他方では、最も複雑なのはデコーダーの実装だけであるためです。足場を建てるのは簡単ですが、超高層ビルを建てるのはそれほど簡単ではありませんが、NIO を学ぶには十分です。
GettyはReactまたはマルチスレッドモデル
を使用します。専用のNIOスレッドがあります。アクセプタースレッドは、サーバーをリッスンし、クライアントのTCP接続リクエストを受信するために使用されます。ワーカー スレッドに割り当てられたワーカー スレッドに接続すると、ワーカー スレッドは読み取りおよび書き込みGetty - Java NIO フレームワーク設計の実装に関する詳細な説明を監視します。
トリガー は対応するGetty - Java NIO フレームワーク設計の実装に関する詳細な説明をトリガーし、 Getty - Java NIO フレームワーク設計の実装に関する詳細な説明 ハンドラー は対応するGetty - Java NIO フレームワーク設計の実装に関する詳細な説明に応答してそれぞれ業務を完了しますサーバー側での処理。
Getty - Java NIO フレームワーク設計の実装に関する詳細な説明定義onRead
: このGetty - Java NIO フレームワーク設計の実装に関する詳細な説明は、クライアントがデータを送信し、ワーカー スレッドによって正しく読み取られたときにトリガーされます。このGetty - Java NIO フレームワーク設計の実装に関する詳細な説明は、クライアントから送信されたデータが実際に処理できることを各Getty - Java NIO フレームワーク設計の実装に関する詳細な説明 ハンドラーに通知します。 onRead
:当客户端发来数据,并已被工作线程正确读取时,触发该事件 。该事件通知各事件处理器可以对客户端发来的数据进行实际处理了。
onWrite
:当客户端可以开始接受服务端发送数据时触发该事件,通过该事件,我们可以向客户端发送响应数据。(当前的实现中并未使用写事件)
onClosed
:当客户端与服务器断开连接时触发该事件。
在这个模型中,事件采用广播方式,也就是所有注册的事件处理器都能获得事件通知。这样可以将不同性质的业务处理,分别用不同的处理器实现,使每个处理器的功能尽可能单一。
如下图:整个事件模型由监听器、事件适配器、事件触发器(HandlerChain,PipeLine)、事件处理器组成。
ServerListener
:这是一个事件接口,定义需监听的服务器事件
interface ServerListener extends Serializable{ /** * 可读事件回调 * @param request */ void onRead(ctx) /** * 可写事件回调 * @param request * @param response */ void onWrite(ctx) /** * 连接关闭回调 * @param request */ void onClosed(ctx) }
EventAdapter
:对 Serverlistener 接口实现一个适配器 (EventAdapter),这样的好处是最终的事件处理器可以只处理所关心的事件。
class EventAdapter implements ServerListener { //下个处理器的引用 protected next void onRead(Object ctx) { } void onWrite(Object ctx) { } void onClosed(Object ctx) { } }
Not<a href="http://www.php.cn/wiki/109.html" target="_blank">if</a>ier
:用于在适当的时候通过触发服务器事件,通知在册的事件处理器对事件做出响应。
interface Notifier extends Serializable{ /** * 触发所有可读事件回调 */ void fireOnRead(ctx) /** * 触发所有可写事件回调 */ void fireOnWrite(ctx) /** * 触发所有连接关闭事件回调 */ void fireOnClosed(ctx) }
HandlerChain
:实现了Notifier
接口,维持有序的事件处理器链条,每次从第一个处理器开始触发。
class HandlerChain implements Notifier{ EventAdapter head EventAdapter tail /** * 添加处理器到执行链的最后 * @param handler */ void addLast(handler) { if (tail != null) { tail.next = handler tail = tail.next } else { head = handler tail = head } } void fireOnRead(ctx) { head.onRead(ctx) } void fireOnWrite(ctx) { head.onWrite(ctx) } void fireOnClosed(ctx) { head.onClosed(ctx) } }
PipeLine
:实现了Notifier
接口,作为事件总线,维持一个事件链的列表。
class PipeLine implements Notifier{ static logger = LoggerFactory.getLogger(PipeLine.name) //监听器队列 def listOfChain = [] PipeLine(){} /** * 添加监听器到监听队列中 * @param chain */ void addChain(chain) { synchronized (listOfChain) { if (!listOfChain.contains(chain)) { listOfChain.add(chain) } } } /** * 触发所有可读事件回调 */ void fireOnRead(ctx) { logger.debug("fireOnRead") listOfChain.each { chain -> chain.fireOnRead(ctx) } } /** * 触发所有可写事件回调 */ void fireOnWrite(ctx) { listOfChain.each { chain -> chain.fireOnWrite(ctx) } } /** * 触发所有连接关闭事件回调 */ void fireOnClosed(ctx) { listOfChain.each { chain -> chain.fireOnClosed(ctx) } } }
Getty - Java NIO フレームワーク設計の実装に関する詳細な説明
事件处理采用职责链模式,每个处理器处理完数据之后会决定是否继续执行下一个处理器。如果处理器不将任务交给线程池处理,那么整个处理流程都在同一个线程中处理。而且每个连接都有单独的PipeLine
onWrite
: このGetty - Java NIO フレームワーク設計の実装に関する詳細な説明は、クライアントがサーバーから送信されたデータの受け入れを開始できるときにトリガーされ、このGetty - Java NIO フレームワーク設計の実装に関する詳細な説明を通じて応答データをクライアントに送信できます。 (現在の実装では書き込みGetty - Java NIO フレームワーク設計の実装に関する詳細な説明は使用されません) 🎜🎜🎜🎜onClosed
: このGetty - Java NIO フレームワーク設計の実装に関する詳細な説明は、クライアントがサーバーから切断されるとトリガーされます。 🎜🎜🎜🎜Getty - Java NIO フレームワーク設計の実装に関する詳細な説明 コールバック メカニズムの実装🎜🎜 このモデルでは、Getty - Java NIO フレームワーク設計の実装に関する詳細な説明はブロードキャストされます。つまり、登録されているすべてのGetty - Java NIO フレームワーク設計の実装に関する詳細な説明 ハンドラーがGetty - Java NIO フレームワーク設計の実装に関する詳細な説明通知を受信できます。このようにして、異なる性質のビジネス処理を異なるプロセッサを使用して実装することができ、各プロセッサの機能を可能な限り単一にすることができます。 🎜🎜以下に示すように: Getty - Java NIO フレームワーク設計の実装に関する詳細な説明 モデル全体は、リスナー、Getty - Java NIO フレームワーク設計の実装に関する詳細な説明 アダプター、Getty - Java NIO フレームワーク設計の実装に関する詳細な説明 トリガー (HandlerChain、PipeLine)、およびGetty - Java NIO フレームワーク設計の実装に関する詳細な説明 プロセッサーで構成されます。 🎜🎜🎜🎜Getty - Java NIO フレームワーク設計の実装に関する詳細な説明処理プロセス🎜🎜🎜🎜プログラミング モデル🎜🎜 Getty - Java NIO フレームワーク設計の実装に関する詳細な説明処理では、各プロセッサがデータの処理を終了した後、次のプロセッサの実行を継続するかどうかを決定します。プロセッサが処理のためにタスクをスレッド プールに渡さない場合、処理プロセス全体が同じスレッドで処理されます。さらに、各接続には個別の PipeLine
があり、ワーカー スレッドは複数の接続コンテキスト間を切り替えることができますが、1 つの接続コンテキストは 1 つのスレッドによってのみ処理されます。 🎜连接上下文ConnectionCtx
class ConnectionCtx { /**socket连接*/ SocketChannel channel /**用于携带额外参数*/ Object attachment /**处理当前连接的工作线程*/ Worker worker /**连接超时时间*/ Long timeout /**每个连接拥有自己的pipeline*/ PipeLine pipeLine }
NioServer
主线程负责监听端口,持有工作线程的引用(使用轮转法分配连接),每次有连接到来时,将连接放入工作线程的连接队列,并唤醒线程selector.wakeup()
(线程可能阻塞在selector
上)。
class NioServer extends Thread { /**服务端的套接字通道*/ ServerSocketChannel ssc /**选择器*/ Selector selector /**事件总线*/ PipeLine pipeLine /**工作线程列表*/ def workers = [] /**当前工作线程索引*/ int index }
工作线程,负责注册server传递过来的socket连接。主要监听读事件,管理socket,处理写操作。
class Worker extends Thread { /**选择器*/ Selector selector /**读缓冲区*/ ByteBuffer buffer /**主线程分配的连接队列*/ def queue = [] /**存储按超时时间从小到大的连接*/ TreeMap<Long, ConnectionCtx> ctxTreeMap void run() { while (true) { selector.select() //注册主线程发送过来的连接 registerCtx() //关闭超时的连接 closeTimeoutCtx() //处理事件 dispatchEvent() } } }
我实现了一系列处理HTTP
请求的处理器,具体实现看代码。
LineBasedDecoder
:行解码器,按行解析数据
HttpRequestDecoder
:HTTP请求解析,目前只支持GET请求
HttpRequestHandler
:Http 请求处理器,目前只支持GET方法
HttpResponseHandler
:Http响应处理器
下面是写在test
中的例子
class WebServerTest { static void main(args) { def pipeLine = new PipeLine() def readChain = new HandlerChain() readChain.addLast(new LineBasedDecoder()) readChain.addLast(new HttpRequestDecoder()) readChain.addLast(new HttpRequestHandler()) readChain.addLast(new HttpResponseHandler()) def closeChain = new HandlerChain() closeChain.addLast(new ClosedHandler()) pipeLine.addChain(readChain) pipeLine.addChain(closeChain) NioServer nioServer = new NioServer(pipeLine) nioServer.start() } }
另外,还可以使用配置文件getty.properties
设置程序的运行参数。
#用于拼接消息时使用的二进制数组的缓存区 common_buffer_size=1024 #工作线程读取tcp数据的缓存大小 worker_rcv_buffer_size=1024 #监听的端口 port=4399 #工作线程的数量 worker_num=1 #连接超时自动断开时间 timeout=900 #根目录 root=.
Getty是我造的第二个小轮子,第一个是RedisHttpSession。都说不要重复造轮子。这话我是认同的,但是掌握一门技术最好的方法就是实践,在没有合适项目可以使用新技术的时候,造一个简单的轮子是不错的实践手段。
Getty 的缺点或者说还可以优化的点:
线程的使用直接用了Thread
类,看起来有点low。等以后水平提升了再来抽象一下。
目前只有读事件是异步的,写事件是同步的。未来将写事件也改为异步的。
以上がGetty - Java NIO フレームワーク設計の実装に関する詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。