乐趣区

关于java:BIO演变NIO的过程

优化 BIO

Bio 是一个阻塞式的 io,不可能反对并发申请拜访; 能够多线程优化代码这种形式也存在毛病:如果每个申请过去都应用一个线程,这时候十分节约 CPU 的资源。所以在网络编程服务器中,是否应用单线程进步响应的效率问题,所以有 NIO 呈现

形式一

每次都会创立线程,十分节约 CPU 的资源

import java.net.InetSocketAddress;

import java.net.ServerSocket;

import java.net.Socket;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class SocketTcpBioServer {

static byte[] bytes = new byte[1024];

public static void main(String[] args) {

try {

// 1. 创立 ServerSocket

final ServerSocket serverSocket = new ServerSocket();

// 2. 绑定端口号

serverSocket.bind(new InetSocketAddress(8080));

while (true) {

System.out.println(“ 开始期待承受数据 …”);

final Socket socket = serverSocket.accept();

new Thread(new Runnable() {

@Override

public void run() {

try {

int read = socket.getInputStream().read(bytes);

String result = new String(bytes);

System.out.println(“ 服务器端获取数据:” + result);

} catch (Exception e) {

}

}

}).start();

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

形式二

通过线程池创立线程,优于计划一有线程回收机制,毛病节约 CPU 的资源
亨达代理申请 https://www.kaifx.cn/broker/h…

import java.io.IOException;

import java.net.InetSocketAddress;

import java.net.ServerSocket;

import java.net.Socket;

import java.util.concurrent.Executor;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class ServerTcpSocket {

static byte[] bytes = new byte[1024];

public static void main(String[] args) {

ExecutorService executorService = Executors.newCachedThreadPool();

try {

// 1. 创立一个 ServerSocket 连贯

final ServerSocket serverSocket = new ServerSocket();

// 2. 绑定端口号

serverSocket.bind(new InetSocketAddress(8080));

// 3. 以后线程放弃 cpu 资源期待获取数据

System.out.println(“ 期待获取数据 …”);

while (true) {

final Socket socket = serverSocket.accept();

executorService.execute(new Runnable() {

public void run() {

try {

System.out.println(“ 获取到数据 …”);

// 4. 读取数据

int read = socket.getInputStream().read(bytes);

String result = new String(bytes);

System.out.println(result);

} catch (Exception e) {

}

}

});

}

} catch (Exception e) {

}

}

}

NIO 设计思维伪代码

多路(多个不同的 tcp 连贯),io 复用:只有一个线程去保护多个不同的 io 操作 最大的益处是:保障线程平安问题、缩小 cpu 调度资源

public class SocketNioTcpServer {

private static List listSocketChannel = new ArrayList<>();

private static ByteBuffer byteBuffer = ByteBuffer.allocate(512);

public static void main(String[] args) {

try {

// 1. 创立一个 ServerSocketChannel

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

// 2. 绑定地址

ServerSocketChannel bind = serverSocketChannel.bind(new InetSocketAddress(8080));

serverSocketChannel.configureBlocking(false);

while (true) {

SocketChannel socketChannel = serverSocketChannel.accept();

if (socketChannel != null) {

socketChannel.configureBlocking(false);

listSocketChannel.add(socketChannel);

}

for (SocketChannel scl : listSocketChannel) {

try {

int read = scl.read(byteBuffer);

if (read > 0) {

byteBuffer.flip();

Charset charset = Charset.forName(“UTF-8”);

String receiveText = charset.newDecoder().decode

(byteBuffer.asReadOnlyBuffer()).toString();

System.out.println(“receiveText:” + receiveText);

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

应用 jdk 原生 api 实现 nio

public class NIOServer {

/**

* 创立一个选择器

*/

private Selector selector;

public void initServer(int port) throws IOException {

// 取得一个 ServerSocketChannel 通道

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

// 设置通道为非阻塞

serverSocketChannel.configureBlocking(false);

// 将该通道对应的 ServerSocket 绑定到 port 端口

serverSocketChannel.bind(new InetSocketAddress(port));

// 取得一个通道管理器

this.selector = Selector.open();

// 将通道管理器和该通道绑定,并为该通道注册 SelectionKey.OP_ACCEPT 事件, 注册该事件后,

// 当该事件达到时,selector.select()会返回,如果该事件没达到 selector.select()会始终阻塞。

serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

}

public void listen() throws IOException {

System.out.println(“ 服务端启动胜利!”);

// 轮询拜访 selector

while (true) {

// 当注册的事件达到时,办法返回; 否则, 该办法会始终阻塞

int select = selector.select();

if (select == 0) {

continue;

}

// 取得 selector 中选中的项的迭代器,选中的项为注册的事件

Iterator ite = this.selector.selectedKeys().iterator();

while (ite.hasNext()) {

SelectionKey key = (SelectionKey) ite.next();

// 删除已选的 key, 以防反复解决

ite.remove();

if (key.isAcceptable()) {// 客户端申请连贯事件

ServerSocketChannel server = (ServerSocketChannel) key.channel();

// 取得和客户端连贯的通道

SocketChannel channel = server.accept();

// 设置成非阻塞

channel.configureBlocking(false);

// 在和客户端连贯胜利之后,为了能够接管到客户端的信息,须要给通道设置读的权限。

channel.register(this.selector, SelectionKey.OP_READ);

} else if (key.isReadable()) {// 取得了可读的事件

read(key);

}

}

}

}

public void read(SelectionKey key) throws IOException {

// 服务器可读取音讯: 失去事件产生的 Socket 通道

SocketChannel channel = (SocketChannel) key.channel();

// 创立读取的缓冲区

ByteBuffer buffer = ByteBuffer.allocate(512);

channel.read(buffer);

byte[] data = buffer.array();

String msg = new String(data).trim();

System.out.println(“ 服务端收到信息:” + msg);

ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes(“utf-8”));

channel.write(outBuffer);// 将音讯回送给客户端

}

public static void main(String[] args) throws IOException {

NIOServer server = new NIOServer();

server.initServer(8000);

server.listen();

}

}

import java.net.InetAddress;

import java.net.InetSocketAddress;

import java.net.Socket;

import java.net.SocketAddress;

import java.util.Scanner;

public class ClientTcpSocket {

public static void main(String[] args) {

try {

Socket socket = new Socket();

SocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(), 8000);

socket.connect(address);

socket.getOutputStream().write(“hello”.getBytes());

} catch (Exception e) {

}

}

}

退出移动版