netty基础01_netty是什么

netty是一个网络编程框架;
如果java应用程序需要与其它程序或设备通信时,需要用到网络编程;
比如:通过java程序远程控制设备开关、接收并处理传感器传递的数据等;
 
1.利用阻塞流的socket
服务端:
public class BioSocket_server {
 
    public static void main(String[] args) throws Exception{
 
        ServerSocket serverSocket = new ServerSocket(8090);    //创建服务端socket
        new Thread(() -> {
            while(true){
                try {
                   Socket socket = serverSocket.accept();    //接收请求
                   new Thread(()->{
                       try {
                            byte[] buf = new byte[1024];
                           InputStream is = socket.getInputStream();    //获取字节流
                           while (true){
                               int len;
                               while((len = is.read(buf)) != -1){
                                   System.out.println(new String(buf, 0, len));    //输出客户端通过字节流传过来的数据
                               }
                           }
                       } catch (Exception e) {
                           e.printStackTrace();
                       }
                   }).start();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
服务端每接收到一个请求,将给该请求创建一个线程;
该线程用字节流读取客户端发送过来的数据,并在控制台输出;
 
客户端:
public class BioSocket_client {
 
    public static void main(String[] args) {
        new Thread(()->{
            try {
                Socket socket = new Socket("127.0.0.1", 8090);    //请求服务端
                while(true){
                    socket.getOutputStream().write((new Date() + " hello ").getBytes());    //发送数据
                    socket.getOutputStream().flush();
                    Thread.sleep(2000);    
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }
}
客户端每2秒给服务端发送一个字符串;
 
结果:
Tue Apr 28 16:20:35 CST 2020hello
Tue Apr 28 16:20:37 CST 2020hello
Tue Apr 28 16:20:39 CST 2020hello
Tue Apr 28 16:20:41 CST 2020hello
Tue Apr 28 16:20:43 CST 2020hello
Tue Apr 28 16:20:45 CST 2020hello
Tue Apr 28 16:20:47 CST 2020hello
Tue Apr 28 16:20:49 CST 2020hello
Tue Apr 28 16:20:51 CST 2020hello
 
这种IO编程模型在客户端较少的情况下运行良好;
但是对于客户端比较多的业务来说,IO模型可能就不太合适了;
比如在上面的例子中:
    每个连接创建成功之后都需要一个线程来维护,
    每个线程包含一个while死循环,
    那么1w个连接对应1w个线程,继而1w个while死循环
 
bio的缺点:
    线程资源受限:线程是操作系统中非常宝贵的资源,同一时刻有大量的线程处于阻塞状态是非常严重的资源浪费,操作系统耗不起
    线程切换效率低下:单机cpu核数固定,线程爆炸之后操作系统频繁进行线程切换,应用性能急剧下降。
    除了以上两个问题,IO编程中,我们看到数据读写是以字节流为单位,效率不高。    
 
2.NIO编程
java1.4引入了非阻塞式流NIO;
与传统的bio( Blocking I/O)相比,nio( Nonblocking I/O)可以一个线程处理多个请求;
优点:更少的内存和上下文切换开销;
 
nio服务端:
public class NIOServer {
    public static void main(String[] args) throws IOException {
        Selector serverSelector = Selector.open();
        Selector clientSelector = Selector.open();
 
        new Thread(() -> {
            try {
                // 对应IO编程中服务端启动
                ServerSocketChannel listenerChannel = ServerSocketChannel.open();
                listenerChannel.socket().bind(new InetSocketAddress(8000));
                listenerChannel.configureBlocking(false);
                listenerChannel.register(serverSelector, SelectionKey.OP_ACCEPT);
 
                while (true) {
                    // 监测是否有新的连接,这里的1指的是阻塞的时间为1ms
                    if (serverSelector.select(1) > 0) {
                        Set<SelectionKey> set = serverSelector.selectedKeys();
                        Iterator<SelectionKey> keyIterator = set.iterator();
 
                        while (keyIterator.hasNext()) {
                            SelectionKey key = keyIterator.next();
 
                            if (key.isAcceptable()) {
                                try {
                                    // (1) 每来一个新连接,不需要创建一个线程,而是直接注册到clientSelector
                                    SocketChannel clientChannel = ((ServerSocketChannel) key.channel()).accept();
                                    clientChannel.configureBlocking(false);
                                    clientChannel.register(clientSelector, SelectionKey.OP_READ);
                                } finally {
                                    keyIterator.remove();
                                }
                            }
                        }
                    }
                }
            } catch (IOException ignored) {
            }
        }).start();
 
        new Thread(() -> {
            try {
                while (true) {
                    // (2) 批量轮询是否有哪些连接有数据可读,这里的1指的是阻塞的时间为1ms
                    if (clientSelector.select(1) > 0) {
                        Set<SelectionKey> set = clientSelector.selectedKeys();
                        Iterator<SelectionKey> keyIterator = set.iterator();
 
                        while (keyIterator.hasNext()) {
                            SelectionKey key = keyIterator.next();
 
                            if (key.isReadable()) {
                                try {
                                    SocketChannel clientChannel = (SocketChannel) key.channel();
                                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                                    // (3) 读取数据以块为单位批量读取
                                    clientChannel.read(byteBuffer);
                                    byteBuffer.flip();
                                    System.out.println(Charset.defaultCharset().newDecoder().decode(byteBuffer)
                                            .toString());
                                } finally {
                                    keyIterator.remove();
                                    key.interestOps(SelectionKey.OP_READ);
                                }
                            }
 
                        }
                    }
                }
            } catch (IOException ignored) {
            }
        }).start();
 
    }}
 
nio的api太过复杂,并且使用不当可能有安全问题;
为了方便使用,需要将其进行封装;
netty就是基于nio开发的网络通信框架;
 
3.netty
需要引入jar包
    <dependency>
        <groupId>io.netty</groupId>
        <artifactId>netty-all</artifactId>
        <version>4.1.6.Final</version>
    </dependency>
 
服务端:
public class NettyServer {
    public static void main(String[] args) {
        ServerBootstrap serverBootstrap = new ServerBootstrap();
 
        NioEventLoopGroup boss = new NioEventLoopGroup();
        NioEventLoopGroup worker = new NioEventLoopGroup();
        serverBootstrap
            .group(boss, worker)
            .channel(NioServerSocketChannel.class)
            .childHandler(new ChannelInitializer<NioSocketChannel>() {
                protected void initChannel(NioSocketChannel ch) {
                    ch.pipeline().addLast(new StringDecoder());
                    ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() {
                        @Override
                        protected void channelRead0(ChannelHandlerContext ctx, String msg) {
                            System.out.println(msg);
                        }
                    });
                }
            })
            .bind(8000);
    }
}
服务端需要2个消息循环组:boss和worker;
boss用来创建新连接;worker用来读取发送过来的信息,并在控制台输出;
 
客户端:
public class NettyClient {
    public static void main(String[] args) throws InterruptedException {
        Bootstrap bootstrap = new Bootstrap();
        NioEventLoopGroup group = new NioEventLoopGroup();
 
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<Channel>() {
                    @Override
                    protected void initChannel(Channel ch) {
                        ch.pipeline().addLast(new StringEncoder());
                    }
                });
 
        Channel channel = bootstrap.connect("127.0.0.1", 8000).channel();
 
        while (true) {
            channel.writeAndFlush(new Date() + ": hello world!");
            Thread.sleep(2000);
        }
    }
}
客户端只需要一个消息循环组
每隔2秒给服务端发送字符串
 
结果:
Tue Apr 28 17:03:38 CST 2020: hello world!
Tue Apr 28 17:03:40 CST 2020: hello world!
Tue Apr 28 17:03:42 CST 2020: hello world!
Tue Apr 28 17:03:44 CST 2020: hello world!
Tue Apr 28 17:03:46 CST 2020: hello world!
Tue Apr 28 17:03:48 CST 2020: hello world!
Tue Apr 28 17:03:50 CST 2020: hello world!
Tue Apr 28 17:03:52 CST 2020: hello world!
Tue Apr 28 17:03:54 CST 2020: hello world!
Tue Apr 28 17:03:56 CST 2020: hello world!

 

 
 
 
 
posted @ 2020-05-29 16:30  L丶银甲闪闪  阅读(106)  评论(0编辑  收藏  举报