美文网首页
JavaWeb之三——网络IO和NIO

JavaWeb之三——网络IO和NIO

作者: 东南一叶 | 来源:发表于2018-10-24 08:59 被阅读0次

TCP状态转换图

影响网络传输的因素

将一份数据从一个地方正确地传输到另一个地方所需要的时间我们称之为响应时间
影响这个时间的因素有很多:

Socket

Java Socket的工作机制

Socket这个概念没有对应到一个具体的实体,它描述计算机之间相互通信的一种抽象功能。
打个比方,可以把Socket比作两个城市之间的交通工具,有了它,就可以在城市之间来回穿梭了。
交通工具有多种,每种交通工具也有相应的交通规则。
Socket也一样,也有多种。大部分情况下我们用的都是基于TCP/IP的流套接字,它是一种稳定的通信协议。

建立通信链路

数据传输

NIO的工作方式

NIO的工作机制

import java.io.IOException;
import java.net.InetSocketAddress;
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.nio.channels.spi.SelectorProvider;
import java.util.Iterator;

/**
 * Created by 18351 on 2018/10/23.
 *
 * TCP/IP的非阻塞方式
 * 服务端
 */
public class Server implements Runnable{
    //第一个端口
    private Integer port1 = 8099;
    //第二个端口
    private Integer port2 = 9099;
    //第一个服务器通道 服务A
    private ServerSocketChannel serversocket1;
    //第二个服务器通道 服务B
    private ServerSocketChannel serversocket2;
    //连接1
    private SocketChannel clientchannel1;
    //连接2
    private SocketChannel clientchannel2;

    //选择器,主要用来监控各个通道的事件
    private Selector selector;

    //缓冲区
    private ByteBuffer buf = ByteBuffer.allocate(512);

    public Server() {
        init();
    }

    /**
     * 这个method的作用 :
     * 1:是初始化选择器
     * 2:打开两个通道
     * 3:给通道上绑定一个socket
     * 4:将选择器注册到通道上
     */
    public void init() {
        try {
            //创建选择器
            this.selector = SelectorProvider.provider().openSelector();
            //打开第一个服务器通道
            this.serversocket1 = ServerSocketChannel.open();
            //告诉程序现在不是阻塞方式的
            this.serversocket1.configureBlocking(false);
            //获取现在与该通道关联的套接字
            this.serversocket1.socket().bind(new InetSocketAddress("localhost", this.port1));
            //将选择器注册到通道上,返回一个选择键
            //OP_ACCEPT用于套接字接受操作的操作集位
            this.serversocket1.register(this.selector, SelectionKey.OP_ACCEPT);

            this.serversocket2=ServerSocketChannel.open();
            this.serversocket2.configureBlocking(false);
            this.serversocket2.socket().bind(new InetSocketAddress("localhost",this.port2));
            this.serversocket2.register(this.selector,SelectionKey.OP_ACCEPT);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 客户端连接服务器
     * @param key
     * @throws IOException
     */
    public void accept(SelectionKey key) throws IOException{
        ServerSocketChannel server = (ServerSocketChannel) key.channel();
        if (server.equals(serversocket1)) {
            clientchannel1 = server.accept(); //连接到服务端1
            clientchannel1.configureBlocking(false);
            //OP_READ用于读取操作的操作集位
            clientchannel1.register(this.selector, SelectionKey.OP_READ);
        } else {
            clientchannel2 = server.accept();////连接到服务端2
            clientchannel2.configureBlocking(false);
            //OP_READ用于读取操作的操作集位
            clientchannel2.register(this.selector, SelectionKey.OP_READ);
        }
    }

    /**
     * 从通道中读取数据
     * 并且判断是给那个服务通道的
     * @throws IOException
     * */
    public void read(SelectionKey key) throws IOException {
        this.buf.clear();
        //通过选择键来找到之前注册的通道
        //但是这里注册的是ServerSocketChannel为什么会返回一个SocketChannel??
        SocketChannel channel = (SocketChannel) key.channel();
        //从通道里面读取数据到缓冲区并返回读取字节数
        int count = channel.read(this.buf);

        if (count == -1) {
            //取消这个通道的注册
            key.channel().close();
            key.cancel();
            return;
        }

        //将数据从缓冲区中拿出来
        String input = new String(this.buf.array()).trim();
        //那么现在判断是连接的那种服务
        if (channel.equals(this.clientchannel1)) {
            System.out.println("欢迎您使用服务A");
            System.out.println("您的输入为:" + input);
        } else {
            System.out.println("欢迎您使用服务B");
            System.out.println("您的输入为:" + input);
        }
    }

    @Override
    public void run() {
        while (true) {
            try {
                System.out.println("running ... ");
                //选择一组键,其相应的通道已为 I/O 操作准备就绪。
                this.selector.select();

                //返回此选择器的已选择键集
                //public abstract Set<SelectionKey> selectedKeys()
                Iterator selectorKeys = this.selector.selectedKeys().iterator();
                while (selectorKeys.hasNext()) {
                    System.out.println("running2 ... ");
                    //这里找到当前的选择键
                    SelectionKey key = (SelectionKey) selectorKeys.next();
                    //然后将它从返回键队列中删除
                    selectorKeys.remove();
                    if (!key.isValid()) { // 选择键无效
                        continue;
                    }
                    if (key.isAcceptable()) {
                        //如果遇到请求那么就响应
                        this.accept(key);
                    } else if (key.isReadable()) {
                        //读取客户端的数据
                        this.read(key);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Server server=new Server();
        Thread thread=new Thread(server);
        thread.start();
    }
}
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

/**
 * Created by 18351 on 2018/10/23.
 * TCP/IP非阻塞方式
 * 客户端
 */
public class Client {
    //创建缓冲区
    private ByteBuffer buffer = ByteBuffer.allocate(512);

    //访问服务器
    public void query(String host, int port) throws IOException {
        InetSocketAddress address = new InetSocketAddress(InetAddress.getByName(host), port);
        SocketChannel socket = null;
        byte[] bytes = new byte[512];
        while (true) {
            try {
                System.in.read(bytes);
                socket = SocketChannel.open();
                socket.connect(address);
                buffer.clear();
                buffer.put(bytes);
                buffer.flip(); //转换读写
                socket.write(buffer);
                buffer.clear();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (socket != null) {
                    socket.close();
                }
            }
        }
    }

    public static void main(String[] args) throws IOException {
        //new Client().query("localhost", 8099);
        new Client().query("localhost", 9099);
    }
}

NIO的主要原理与使用

Buffer的工作方式

NIO的文件访问方式

相关文章

  • JavaWeb之三——网络IO和NIO

    TCP状态转换图 影响网络传输的因素 Socket NIO的主要原理与使用 Buffer的工作方式 NIO的文件访...

  • Reactor模式

    关键词:Reactor模式 IO NIO 阻塞 异步 阻塞/异步概念:读网络教科书 Java NIO和IO区...

  • java Nio

    NIO编程 网络IO的介绍 nio的概述 通道、 缓冲区、 选择器 网络IO 讲网络IO前,我们先对同步、异步、阻...

  • IO/NIO/AIO & Netty

    IO/NIO/AIO 的区别: IO和NIO 又称为Blocking IO 和 No Blocking IO 即为...

  • Java NIO

    1、IO和NIO的区别? 1)IO面向流、NIO面向缓冲;2)IO是阻塞IO、NIO是非阻塞IO;3)无 与 选择...

  • NIO学习总结

    NIO NIO称为Non-blocking I/O 或 New I/O,就是非阻塞IO或者新IO BIO网络模型 ...

  • javaNIO

    一.NIO的由来 传统的BIO即阻塞IO,不管是磁盘IO还是网络IO,在写入和读取的时候,因为内存和硬盘或网络的读...

  • JAVA过关题-NIO是什么?适用于何种场景

    BIO(Blocking-IO)和NIO(Non-Blocking-IO或New IO)是两种不同的网络通信模型,...

  • Java NIO 和 IO 之间的主要差别

    NIO 和 IO 之间的主要差别 IO NIO 面向流 面向缓冲 阻塞IO 非阻塞IO 无 ...

  • java NIO详解

    NIO原理 NIO与IO的区别 首先来讲一下传统的IO和NIO的区别,传统的IO又称BIO,即阻塞式IO,NIO就...

网友评论

      本文标题:JavaWeb之三——网络IO和NIO

      本文链接:https://www.haomeiwen.com/subject/sbqttqtx.html