>  기사  >  Java  >  Java NIO 프레임워크 설계 구현에 대한 Getty의 자세한 설명

Java NIO 프레임워크 설계 구현에 대한 Getty의 자세한 설명

黄舟
黄舟원래의
2017-03-24 10:46:011972검색

머리말

Getty는 Java NIO를 배우기 위해 작성한 NIO 프레임워크로, 구현 과정에서 Netty의 설계를 참고하고 Groovy를 사용하여 구현했습니다. 비록 장난감일 뿐이지만 참새는 작고 내부 장기가 모두 들어있습니다. 구현 과정에서 NIO 사용법에 익숙해졌을 뿐만 아니라 네티의 디자인 아이디어도 많이 배워 코딩 능력과 디자인 능력이 향상되었습니다. .

Groovy를 사용하여 작성하는 이유는 Groovy를 방금 배우고 실습에 사용했기 때문입니다. 또한 Groovy는 Java와 호환되므로 차이점은 여전히 ​​기본 구현입니다. Java API 기반입니다.

Getty의 핵심 코드 줄은 한편으로는 Groovy의 간결한 구문의 이점을 누리기도 하고, 다른 한편으로는 핵심 로직만 구현했기 때문에 실제로 가장 복잡한 것은 디코더입니다. 구현. 비계는 만들기 쉽지만 초고층 건물을 짓는 것은 그리 쉽지 않지만 NIO를 배우기에는 충분합니다.

스레드모델

Getty는 React또는 멀티스레드 모델

Java NIO 프레임워크 설계 구현에 대한 Getty의 자세한 설명

    을 사용하고 있습니다.
  1. 전용 NIO 스레드가 있습니다. Acceptor 스레드는 서버를 모니터링하고 클라이언트의 TCP 연결 요청을 수신한 다음 읽기 및 쓰기 이벤트를 모니터링하는 작업자 스레드에 연결을 할당하는 데 사용됩니다. .

  2. 네트워크 IO 작업 - 읽기/쓰기 등은 메시지 읽기, 디코딩, 인코딩 및 전송을 담당하는 여러 작업자 스레드를 담당합니다.

  3. 1개의 작업자 스레드는 N개의 링크를 동시에 처리할 수 있지만, 동시 작업 문제를 방지하기 위해 1개의 링크는 1개의 작업자 스레드에만 대응됩니다.

이벤트 중심 모델

전체 서버 측 프로세스 처리는 이벤트 메커니즘을 기반으로 합니다. [연결 수락 -> 읽기 -> 비즈니스 처리 -> 쓰기 -> 연결 끊기] 과정에서 트리거 가 해당 이벤트를 트리거하고, 이벤트 핸들러 가 해당 이벤트를 처리합니다. 서버 측 비즈니스 처리를 완료하기 위한 응답입니다.

이벤트 정의

  1. onRead: 이 이벤트는 클라이언트가 데이터를 보내고 작업자 스레드에서 올바르게 읽었을 때 트리거됩니다. 이 이벤트는 클라이언트가 보낸 데이터가 실제로 처리될 수 있음을 각 이벤트 핸들러에 알립니다.

  2. onWrite: 이 이벤트는 클라이언트가 서버에서 보낸 데이터를 수락하기 시작할 때 트리거되며, 이 이벤트를 통해 클라이언트에 응답 데이터를 보낼 수 있습니다. (현재 구현에서는 쓰기 이벤트가 사용되지 않습니다.)

  3. onClosed: 이 이벤트는 클라이언트가 서버와 연결을 끊을 때 트리거됩니다.

이벤트 콜백 메커니즘 구현

이 모델에서는 이벤트가 브로드캐스트됩니다. 즉, 등록된 모든 이벤트 핸들러가 이벤트 알림을 받을 수 있습니다. 이러한 방식으로 다양한 성격의 비즈니스 처리를 다양한 프로세서를 사용하여 구현할 수 있으므로 각 프로세서의 기능을 최대한 단일하게 만들 수 있습니다.

아래와 같이 전체 이벤트 모델은 리스너, 이벤트 어댑터, 이벤트 트리거(HandlerChain, PipeLine) 및 이벤트 프로세서로 구성됩니다.

Java NIO 프레임워크 설계 구현에 대한 Getty의 자세한 설명

  • 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)를 구현하면 최종 이벤트 프로세서가 관련 이벤트만 처리할 수 있다는 장점이 있습니다.

    아아아아
  • 아닙니다<a href="http://www.php.cn/wiki/109.html" target="_blank">만약<code>Not<a href="http://www.php.cn/wiki/109.html" target="_blank">if</a>ier: 적절한 시간에 서버 이벤트를 트리거하여 이벤트에 응답하도록 등록된 이벤트 핸들러에게 알리는 데 사용됩니다.

    class EventAdapter implements ServerListener {
        //下个处理器的引用
        protected next
        void onRead(Object ctx) {
        }
        void onWrite(Object ctx) {
        }
        void onClosed(Object ctx) {
        }
    }
  • HandlerChain: 매번 첫 번째 핸들러에서 트리거되는 질서 있는 이벤트 핸들러 체인을 유지하기 위해 Notifier 인터페이스를 구현합니다.

    interface Notifier extends Serializable{
        /**
         * 触发所有可读事件回调
         */
        void fireOnRead(ctx)
        /**
         * 触发所有可写事件回调
         */
        void fireOnWrite(ctx)
        /**
         * 触发所有连接关闭事件回调
         */
        void fireOnClosed(ctx)
    }
  • PipeLine: 이벤트 체인 목록을 유지하기 위해 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)
        }
    }

이벤트 처리 프로세스

Java NIO 프레임워크 설계 구현에 대한 Getty의 자세한 설명

프로그래밍 모델

이벤트 처리는 책임 사슬 모델, 각 프로세서를 채택합니다. 데이터 처리가 끝나면 다음 프로세서를 계속 실행할지 여부가 결정됩니다. 프로세서가 처리를 위해 작업을 스레드 풀에 넘겨주지 않으면 전체 처리 프로세스가 동일한 스레드에서 처리됩니다. 그리고 각 연결에는 별도의 PipeLine이 있으며 작업자 스레드는 여러 연결 컨텍스트 간에 전환할 수 있지만 하나의 연결 컨텍스트는 하나의 스레드에서만 처리됩니다.

核心类

ConnectionCtx

连接上下文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
}

Worker

工作线程,负责注册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()
        }
    }
}

运行一个简单的 Web 服务器

我实现了一系列处理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 的缺点或者说还可以优化的点:

  1. 线程的使用直接用了Thread类,看起来有点low。等以后水平提升了再来抽象一下。

  2. 目前只有读事件是异步的,写事件是同步的。未来将写事件也改为异步的。

위 내용은 Java NIO 프레임워크 설계 구현에 대한 Getty의 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.