BIO 伪异步IO NIO 说明示例

本文介绍了网络IO编程中的三种模型:传统阻塞IO(BIO)、伪异步IO以及非阻塞IO(NIO)。BIO方式下,每个请求都会开启新的线程处理;伪异步IO通过线程池实现,提高效率;NIO利用选择器监听通道,实现高效的数据读写。测试这些模型可使用telnet工具。
摘要由CSDN通过智能技术生成

网络IO编程基本模型是C/S,即客户端服务端通信。但对于传统通信方式服务会被阻塞。下面介绍几种非同步通信方式。

  • BIO 开启单独线程进行端口监听,对每个请求开启一个线程进行相应
  • 伪异步IO 服务端开启一个线程池,请求从线程池中随机取出一个可用线程进行处理。
  • NIO 使用seletor选择器对通道进行监听,通道负责和缓存区进行数据的读写。
1. 传统方式

在这里插入图片描述
示例:
final Socket socket = serverSocket.accept();程序会阻塞

package com.hiro.learn.normal;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * Project: learn
 *
 * @author : hirolin
 * @date : 2019/5/23 10:20
 */
public class OioServer {

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8000);
        System.out.println("server started");

        while (true) {
            final Socket socket = serverSocket.accept();
            System.out.println("client connected!");
            handle(socket);
        }
    }

    public static void handle(Socket socket) {
        try {
            byte[] bytes = new byte[1024];
            InputStream inputStream = socket.getInputStream();
            while (true) {
                int read = inputStream.read(bytes);
                if (read != -1) {
                    System.out.println(new String(bytes, 0, read));
                } else {
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                System.out.println("socket close");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }
}
2.BIO 线程池方式

在这里插入图片描述
在这里插入图片描述

package com.hiro.learn.bio;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Project: learn
 *
 * @author : hirolin
 * @date : 2019/5/23 10:20
 */
public class BioServer {

    public static void main(String[] args) throws IOException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        ServerSocket serverSocket = new ServerSocket(8000);
        System.out.println("server started");

        while (true) {
            final Socket socket = serverSocket.accept();
            System.out.println("client connected!");
            executorService.execute(new Runnable() {
                                        @Override
                                        public void run() {
                                            System.out.println(socket.getPort());
                                            handle(socket);
                                        }
                                    }
            );

        }
    }

    public static void handle(Socket socket) {
        try {
            byte[] bytes = new byte[1024];
            InputStream inputStream = socket.getInputStream();
            while (true) {
                int read = inputStream.read(bytes);
                if (read != -1) {
                    System.out.println(new String(bytes, 0, read));
                } else {
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                System.out.println("socket close");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }
}
3.NIO

在这里插入图片描述

package com.hiro.learn.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.util.Iterator;

/**
 * Project: learn
 *
 * @author : hirolin
 * @date : 2019/5/23 0:04
 */
public class NIOService {

    //通道管理器
    private Selector selector;

    /**
     * 1.获取serverChannel通道
     * 2.设置通道为非阻塞
     * 3.将通道绑定端口
     * 4.获取selector选择器
     * 5.将serverChannel通道注册到selector选择器,指定事件类型
     * * @param port
     * @throws IOException
     */
    public void initServer(int port) throws IOException {
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        serverChannel.configureBlocking(false);
        serverChannel.socket().bind(new InetSocketAddress(port));
        this.selector = Selector.open();
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
    }

    /**
     * 1.使用轮询的方式进行事件响应 select() 会一直阻塞
     * 2.获取响应的事件
     * 3.遍历
     *   3.1删除当前处理的key
     *   3.2获取当前通道 进行数据传输
     * @throws IOException
     */
    @SuppressWarnings("unchecked")
    public void listen() throws IOException {
        System.out.println("server started .... ");
        while (true) {
            selector.select();
            Iterator ite = this.selector.selectedKeys().iterator();
            while (ite.hasNext()) {
                SelectionKey key = (SelectionKey) ite.next();
                ite.remove();
                if (key.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) key
                            .channel();
                    SocketChannel channel = server.accept();
                    channel.configureBlocking(false);
                    channel.write(ByteBuffer.wrap(new String("send client message by server").getBytes()));
                    channel.register(this.selector, SelectionKey.OP_READ);
                } else if (key.isReadable()) {
                    read(key);
                }

            }

        }
    }
    /**
     * 处理读取客户端发来的信息 的事件
     * @param key
     * @throws IOException
     */
    public void read(SelectionKey key) throws IOException{
        SocketChannel channel = (SocketChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(10);
        channel.read(buffer);
        byte[] data = buffer.array();
        String msg = new String(data).trim();
        System.out.println("server receive:"+msg);
        ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes());
        channel.write(outBuffer);// 将消息回送给客户端
    }

    /**
     * main
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        NIOService server = new NIOService();
        server.initServer(8000);
        server.listen();
    }
}

测试方法可以使用telnet 127.0.0.1 8000进行链接,启动多个窗口
(window需要先安装 win7安装之后可能要重启一下)在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值