JAVA BIO/NIO Demo分析

58 篇文章 0 订阅
本文介绍了Java Socket编程中BIO(阻塞I/O)和NIO(非阻塞I/O)的工作原理及区别。在BIO模式下,每个连接都需要一个线程处理,可能导致线程资源浪费。而NIO通过Selector实现单线程多路复用,提高了效率。文中提供了BIO和NIO的示例代码,展示了它们在处理客户端连接和数据读写时的不同处理方式。
摘要由CSDN通过智能技术生成

BIO 阻塞io  NIO非阻塞io
java Socket编程中的这两种方式 我的理解是 BIO在Server.accept接收到连接请求后,开启一个线程处理此请求,io操作(客户端写入)时,该线程阻塞,客户端写入完毕后,该线程读取信息开始处理。这里存在一个过程,若客户端写操作耗时长,服务端线程等待,白白浪费线程资源,若是并发量大,服务端可能承受不住,这里可以做线程池来优化,但是还是没有避免线程中需要等待客户端写操作完成。
NIO则不然,单线程中使用多路复用器Selector阻塞监听多个Channel的事件(包括Server端的监听连接事件、客户端的写入完毕事件),若存在就绪的Channel,开启线程处理消息,避免了客户端写入时的线程阻塞

以下是java BIO和NIO示例代码

BIO 阻塞监听连接,一个连接对应一个线程处理(可ThreadPoolExecutor线程池优化)

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

public class BIOTest {

    public static void main(String[] args) throws IOException {
        System.out.println("socket tcp服务器端启动....");
        ServerSocket serverSocket = new ServerSocket(8080);
        // 等待客户端请求
        try {
            while (true) {
                System.out.println("服务器等待新连接。。。。。。。。。。");
                Socket accept = serverSocket.accept();
                System.out.println("服务器有了新连接。。。。。。。。。。");
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            InputStream inputStream = accept.getInputStream();
                            // 转换成string类型
                            byte[] buf = new byte[1024];
                            System.out.println("线程开始read。。。。。。。。。。");
                            int len = inputStream.read(buf);
                            System.out.println("线程结束read。。。。。。。。。。");
                            String str = new String(buf, 0, len);
                            System.out.println("服务器接受客户端内容:" + str);
                        } catch (Exception e) {
                        }
                    }
                }).start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            serverSocket.close();
        }
    }


}

class TcpClient {
    public static void main(String[] args) throws UnknownHostException, IOException {
        System.out.println("socket tcp 客户端启动....");
        Socket socket = new Socket("127.0.0.1", 8080);
        System.out.println("客户端线程getOutputStream。。。。。。。。。。");
        OutputStream outputStream = socket.getOutputStream();
        System.out.println("客户端线程write。。。。。。。。。。");
        outputStream.write("我是客户端".getBytes());
        socket.close();
    }

}

启动服务端

客户端代码在写入数据行打上断点,模拟耗时操作

可以看到,客户端连接服务端已经接收到,阻塞在read方法

 F8完毕

 

NIO代码   Selector监听,如果是连接操作,再注册对应channel的读事件继续监听,如果读就绪,开始处理,线程不需要等待客户端动作

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.Date;
import java.util.Iterator;

public class NIOTest {
    public static void main(String[] args) throws IOException {
        System.out.println("服务器端已经被启动。。。。。。");
  
        ServerSocketChannel socketChannel = ServerSocketChannel.open();
        // 非阻塞
        socketChannel.configureBlocking(false);
        // 绑定端口
        socketChannel.bind(new InetSocketAddress(8080));
        // 多路复用器
        Selector selector=Selector.open();
        //将socketChannel注册到选择器中 并且指定其监听连接事件
        socketChannel.register(selector,SelectionKey.OP_ACCEPT);
        // 轮询获取就绪的事件
        while(selector.select()>0){
            //获取当前选择器中所有已经注册的selectedKey
            Iterator<SelectionKey> selectionKeys = selector.selectedKeys().iterator();
            while(selectionKeys.hasNext()){
                //获取就绪事件
                SelectionKey selectionKey = selectionKeys.next();
              
			    // 连接就绪
                if(selectionKey.isAcceptable()){
					// 注册客户端clientChannel读事件
                    SocketChannel clientChannel = socketChannel.accept();
                    clientChannel.configureBlocking(false);
                    clientChannel.register(selector,SelectionKey.OP_READ);
                }
				
				if(selectionKey.isReadable()){
                    // 客户端Channel读就绪
                    SocketChannel channel = (SocketChannel) selectionKey.channel();
                    // 读取数据
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    // 把channel中的数据读取到buffer
                    clientChannel.read(buffer);

                    // 开始处理
                }
				
                selectionKeys.remove();
            }
        }
    }
}


class NIOClient {
    public static void main(String[] args) throws IOException {
        System.out.println("客户端已经启动。。。");
        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8080)); 
        socketChannel.configureBlocking(false); 
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        buffer.put("略略略".toString().getBytes());
        buffer.flip();//切换到读取模式
        socketChannel.write(buffer);
        buffer.clear();
        socketChannel.close();
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值