传输

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

  从阻塞传输切换到非阻塞传输,那么你可能会因为这两种网络 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!\r\n".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!\r\n".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 中)使用了这个传输的服务器端时也必须使用它。除了这个限制,它的 使用方式和其他的传输一模一样。

posted @ 2021-04-25 15:03  smartcat994  阅读(220)  评论(0编辑  收藏  举报