优化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) {

}

}

}


zhuanzhudeyipi
65 声望2 粉丝