开源框架学习-Netty (一)

话说鄙人最近有点恐惧,从百度上搜的词叫做恐怖型焦虑障碍,估计人到中年了,需要学习了。害怕被社会脱轨!

于是,开始了学习之旅,首先聊聊netty.标准rpc框架之一。大家都知道,之前都了解mina等等,都是rpc,如今最火的应该就是这个了。

说起这个,还是要从io说起,先介绍下io吧,有阻塞io,非阻塞io.多路io.等等,慢慢来,一个个介绍,顺便也给大家介绍下历程,从最初开始的阻塞式io,到非阻塞式IO.

IO请求的两个阶段

等待资源阶段

IO请求一般需要请求特殊的资源(如磁盘、RAM、文件),当资源被上一个使用者使用没有被释放时,IO请求就会被阻塞,直到能够使用这个资源。

使用资源阶段

真正进行数据接收和发生。

在等待数据阶段,IO分为阻塞IO和非阻塞IO。

阻塞IO

资源不可用时,IO请求一直阻塞,直到反馈结果(有数据或超时)。

非阻塞IO

资源不可用时,IO请求离开返回,返回数据标识资源不可用


阻塞式io

贴一张图,

 

用一个例子说明下:

  (1)我和女友点完餐后,不知道什么时候能做好,只好坐在餐厅里面等,直到做好,然后吃完才离开。

女友本想还和我一起逛街的,但是不知道饭能什么时候做好,只好和我一起在餐厅等,而不能去逛街,直到吃完饭才能去逛街,中间等待做饭的时间浪费掉了。这就是典型的阻塞。网络中IO阻塞如下图所示:

非阻塞IO

(2)我女友不甘心白白在这等,又想去逛商场,又担心饭好了。所以我们逛一会,回来询问服务员饭好了没有,来来回回好多次,饭都还没吃都快累死了啦。这就是非阻塞。需要不断的询问,是否准备好了。网络IO非阻塞如下图所示:

IO多路复用

(3)与第二个方案差不多,餐厅安装了电子屏幕用来显示点餐的状态,这样我和女友逛街一会,回来就不用去询问服务员了,直接看电子屏幕就可以了。这样每个人的餐是否好了,都直接看电子屏幕就可以了,这就是典型的IO多路复用,如select、poll、epoll。网络IO具体模型如下图所示:

使用select()接口的基于事件驱动的服务器模型

  (4)女友不想逛街,又餐厅太吵了,回家好好休息一下。于是我们叫外卖,打个电话点餐,然后我和女友可以在家好好休息一下,饭好了送货员送到家里来。这就是典型的异步,只需要打个电话说一下,然后可以做自己的事情,饭好了就送来了。linux提供了AIO库函数实现异步,但是用的很少。目前有很多开源的异步IO库,例如libevent、libev、libuv。异步过程如下图所示:'

 

下面来看看代码的转换;socket为例;

package me.duzhi.demo.socket;

import org.apache.log4j.net.SocketServer;

import java.io.*;
import java.net.*;

public class BlockingSocket {
    public static void main(String[] args) throws IOException {
        ServerSocket socketServer = new ServerSocket(89);

        while (true){
            Socket socket = socketServer.accept();
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
            ...
        }
    }
}

 

上面的问题,可以看到,所有的节点都是等待1各个的完成,然而就会出现,所有的返回需要等待处理完;好,我们做点优化;

public class Socket2 {
    public static void main(String[] args) throws IOException {
        ServerSocket socketServer = new ServerSocket(89);
        //创建线程池制作伪线程状态
        ExecutorService service = Executors.newFixedThreadPool(200);

        while (true){
            Socket socket = socketServer.accept();
            service.execute(new Execute(socket));
        }
    }

    public static class Execute implements Runnable {
        private Socket socket;

        public Execute(Socket socket) {
            this.socket = socket;
        }

        public void run() {

            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
            
        }
    }
}

 

想想上面这个有什么缺点?

 当对Socket的输入流进行读取操作的时候,它会一直阻塞下去,一直发生下面三种事件。

(1)有数据可读

(2)可用数据已经读取完毕

(3)发生空指针和IO异常

  这意味着对方发送请求或者应答时间比较缓慢、或者网络传输较慢时,读取输入流一方的通信线程将长时间阻塞,如果对方要60s才能将数据发送完成,读取一方的IO线程也将会被同步阻塞60s,在此期间,其他接入消息只能在消息队列中排队。

先不写了,下一篇咱说说非阻塞式。

 

除特别注明外,本站所有文章均为duzhi原创,转载请注明出处来自https://www.duzhi.me/article/12763.html

联系我们

******

在线咨询:点击这里给我发消息

邮件:ashang.peng#aliyun.com

QR code