• 传输


      流经网络的数据总是具有相同的类型:字节。这些字节是如何流动的主要取决于我们所说的 网络传输—一个帮助我们抽象底层数据传输机制的概念。用户并不关心这些细节;他们只想确 保他们的字节被可靠地发送和接收。——————>字符流构建在字节流基础之上(通常还要传入一个字符集编码作为参数),为方便读取“文本文件”而设计的。字符流专门用于读取文本文件。字符更加的全面。

      从阻塞传输切换到非阻塞传输,那么你可能会因为这两种网络 API 的截然不同而遇到问题————>Socket转化为NioSocket

    不使用BIO以及NIO

      阻塞版demo:

    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.nio.charset.Charset;
    
    public class PlainOioServer {
        public void serve(int port) throws IOException {
            //将服务器绑定到指定端口
            final ServerSocket socket = new ServerSocket (port);
            try {
                for (;;) {
                    //接受连接
                    final Socket clientSocket = socket.accept();
                    System.out.println(
                            "Accepted connection from " + clientSocket);
                    //创建一个新的线程来处理该连接
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            OutputStream out;
                            try {
                                out = clientSocket.getOutputStream();
                                out.write("Hi!
    ".getBytes(
                                        Charset.forName("UTF-8")));
                                out.flush();
                                clientSocket.close();
                            }
                            catch (IOException e) {
                                e.printStackTrace();
                            }
                            finally {
                                try {
                                    clientSocket.close();
                                }
                                catch (IOException ex) {
                                }
                            }
                        }
                    }).start();
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

      非阻塞版demo:

    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.net.ServerSocket;
    import java.nio.ByteBuffer;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.ServerSocketChannel;
    import java.nio.channels.SocketChannel;
    import java.util.Iterator;
    import java.util.Set;
    
    public class PlainNioServer {
        public void serve(int port) throws IOException {
            ServerSocketChannel serverChannel = ServerSocketChannel.open();
            serverChannel.configureBlocking(false);
            ServerSocket ssocket = serverChannel.socket();
            //绑定特定端口
            InetSocketAddress address = new InetSocketAddress(port);
            ssocket.bind(address);
            //打开轮训器来处理Channel
            Selector selector = Selector.open();
            //指定的Socket挂在到selector上
            serverChannel.register(selector, SelectionKey.OP_ACCEPT);
            final ByteBuffer msg = ByteBuffer.wrap("Hi!
    ".getBytes());
            for (;;) {
                try {
                    //等待需要处理的新事件;阻塞将一直持续到下一个传入事件
                    selector.select();
                } catch (IOException ex) {
                    ex.printStackTrace();
                    break;
                }
                //获取所有接收事件的SelectionKey 实例
                Set<SelectionKey> readyKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = readyKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    iterator.remove();
                    try {
                        //检查事件是否是一个新的已经就绪可以被接受的连接
                        if (key.isAcceptable()) {
                            ServerSocketChannel server =
                                    (ServerSocketChannel)key.channel();
                            SocketChannel client = server.accept();
                            client.configureBlocking(false);
                            client.register(selector, SelectionKey.OP_WRITE |
                                    SelectionKey.OP_READ, msg.duplicate());
                            System.out.println(
                                    "Accepted connection from " + client);
                        }
                        if (key.isWritable()) {
                            SocketChannel client =
                                    (SocketChannel)key.channel();
                            ByteBuffer buffer =
                                    (ByteBuffer)key.attachment();
                            while (buffer.hasRemaining()) {
                                if (client.write(buffer) == 0) {
                                    break;
                                }
                            }
                            client.close();
                        }
                    } catch (IOException ex) {
                        key.cancel();
                        try {
                            key.channel().close();
                        } catch (IOException cex) {
                        }
                    }
                }
            }
        }
    }

      使用Netty版demo:

    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.oio.OioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    import io.netty.channel.socket.oio.OioServerSocketChannel;
    
    import java.net.InetSocketAddress;
    
    /**
     * description: EchoServer
     * date: 2021/4/21 17:57
     *
     * @author: SmartCat
     * version: 1.0.0
     */
    public class EchoServer {
        private void start() throws InterruptedException {
            EchoServerHandler echoServerHandler = new EchoServerHandler ();
            NioEventLoopGroup group = new NioEventLoopGroup ();
    
            try{
                ServerBootstrap serverBootstrap = new ServerBootstrap ();
                serverBootstrap.group(group,group)
                        .channel (OioServerSocketChannel.class)
                        .localAddress (new InetSocketAddress (8088))
                        .childHandler (new ChannelInitializer<SocketChannel> () {
                            @Override
                            protected void initChannel(SocketChannel socketChannel) throws Exception {
                                socketChannel.pipeline ().addLast (echoServerHandler);
    //                            socketChannel.pipeline ().addLast (new EchoClientHandler ());
                                System.out.println ("已经添加完毕");
                            }
                        });
                ChannelFuture f = serverBootstrap.bind ().sync ();
                f.channel ().closeFuture ().sync ();
            } catch (InterruptedException e) {
                e.printStackTrace ();
            } finally {
                group.shutdownGracefully ().sync ();
            }
        }

      传输 API 的核心是 interface Channel,它被用于所有的 I/O 操作。每个 Channel 都将会被分配一个 ChannelPipeline 和 ChannelConfig。 ChannelConfig 包含了该 Channel 的所有配置设置,并且支持热更新。由于特定的传输可能 具有独特的设置,所以它可能会实现一个 ChannelConfig 的子类型。

       为什么会继承Cpmarable。由于 Channel 是独一无二的,所以为了保证顺序将 Channel 声明为 java.lang. Comparable 的一个子接口。因此,如果两个不同的 Channel 实例都返回了相同的散列码,那 么 AbstractChannel 中的 compareTo()方法的实现将会抛出一个 Error。ChannelPipeline 持有所有将应用于入站和出站数据以及事件的 ChannelHandler 实 例,这些 ChannelHandler 实现了应用程序用于处理状态变化以及数据处理的逻辑。

      每个 Channel 都将会被分配一个 ChannelPipeline 和 ChannelConfig。 ChannelConfig包含了该 Channel的所有配置设置,并且支持热更新。由于特定的传输可能 具有独特的设置,所以它可能会实现一个 ChannelConfig的子类型。ChannelPipeline 持有所有将应用于入站和出站数据以及事件的   ChannelHandler 实 例,这些  ChannelHandler实现了应用程序用于处理状态变化以及数据处理的逻辑。

      ChannelHandler的典型用途包括:将数据从一种格式转换为另一种格式;提供异常的通知;提供 Channel变为活动的或者非活动的通知;提供当 Channel注册到 EventLoop或者从 EventLoop注销时的通知;提供有关用户自定义事件的通知。

      你也可以根据需要通过添加或者移除ChannelHandler实例来修改ChannelPipeline。

      Netty 的 Channel实现是线程安全的,因此你可以存储一个到 Channel的引用,并且每当 你需要向远程节点写数据时,都可以使用它,即使当时许多线程都在使用它。

      Netty的NIO的实现也是依赖JDK1.4时便可用的一个基于选择器的API,选择器背后的逻辑是充当一个注册表,在拿了你可以将请求在Chanel的状态发送变化时得到新通知。之前说过Channel等同于Socket的概念。

      可能的状态变化有:新的channel已被接收且就绪;Channel连接已经完成;Channel有已经就绪的可供读取的数据;Channel可用于写数据

      选择器运行在一个检查状态变化并对其做出相应响应的线程上,在应用程序对状态的改变做 出响应之后,选择器将会被重置,并将重复这个过程。

     

    用于 JVM 内部通信的 Local 传输

       Netty 提供了一个  Local 传输,用于在同一个  JVM 中运行的客户端和服务器程序之间的异步 通信。同样,这个传输也支持对于所有 Netty 传输实现都共同的  API。在这个传输中,和服务器 Channel相关联的 SocketAddress并没有绑定物理网络地址;只要服务器还在运行,它就会被存储在注册表里,并在 Channel关闭时注销。因为这个 传输并不接受真正的网络流量,所以它并不能够和其他传输实现进行互操作。因此,客户端希望 连接到(在同一个 JVM 中)使用了这个传输的服务器端时也必须使用它。除了这个限制,它的 使用方式和其他的传输一模一样。

    smartcat.994
  • 相关阅读:
    iptables的state模块的4种封包链接状态
    添加网络设备eth0
    DOM对象与jquery对象有什么不同
    A Death in the Family May Cause Real Heart Break
    A Soft Body, but the Mind of a Robot
    Oeasy系列教程
    浏览器中的javascript
    递归算法详细分析
    Axure 运行开发工具
    Hello Mono 转载的Mono Project Tutorial
  • 原文地址:https://www.cnblogs.com/SmartCat994/p/14690397.html
Copyright © 2020-2023  润新知