计算机网络:Socket编程-NIO进行优化
上篇写了计算机网络:Socket编程-多线程优化和请求响应对象封装,
有留心的伙伴就会发现,我先是简单写了一个HTTP服务,然后对这个HTTP服务进行面向对象封装,接着又在封装的基础上进行多线程的优化和请求响应对象的封装,这样一步一步的由简入深。
这篇也是继续深入优化,之前的代码都是使用ServerSocket这个类,从代码中可以看出,它是每个请求都需要单独的线程进行处理,ServerSocket是基于阻塞I/O模型。那有没有非阻塞模式类?
有的,Java NIO库中提供了ServerSocketChannel这个类,它是通过Selector来管理多个通道的,一个线程可以处理多个请求。
1、NIO
- 过程:
1(用户请求)-> 2(Pending Queue收集)-> 3、4、5(线程触发Accept,内核从Pending Queue获取一个请求,形成一个Socket文件,拿到文件句柄)-> 6(线程将Socket注册到Selector中,也将内容信息存入Buffer中,放入Channel中)-> 7(工作线程通过响应式获取Channel里的信息)-> 8(工作线程先读取Channel信息,处理完请求后将相关信息写入Buffer,通过Channel再传递给内核)-> 9(内核监听到Socket文件写入信息然后再返回给请求方)
代码实现
package com.hh.http;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Function;
/**
* NIO进步优化
*
* @author hang.yuan 2022/3/8 19:50
*/
public class HttpServer4 {
ServerSocketChannel ssc;
public void listen(int port) throws IOException {
ssc = ServerSocketChannel.open();
ssc.bind(new InetSocketAddress(port));
// Reactive / Reactor
ssc.configureBlocking(false);
Selector selector = Selector.open();
ssc.register(selector,ssc.validOps(),null);
ByteBuffer buffer = ByteBuffer.allocate(1024*16);
for(;;){
int numOfKeys = selector.select();
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> it = selectionKeys.iterator();
while (it.hasNext()){
SelectionKey key = it.next();
if (key.isAcceptable()){
SocketChannel channel = ssc.accept();
if (channel == null){
continue;
}
// Kernel --> mmap(buffer) --> Channel --> User(buffer)
channel.configureBlocking(false);
channel.register(selector,SelectionKey.OP_READ);
}else {
SocketChannel channel = (SocketChannel)key.channel();
//_ _ _ _ _ _ _
// P(position)
// L
buffer.clear();
channel.read(buffer);
String request = new String(buffer.array());
//Logic ...
buffer.clear();
buffer.put("HTTP/1.1 200 ok\n\nHello NIO!\n".getBytes());
// H T T P / 1 ... ! _ _
// P(L)
// P L
buffer.flip();//就是把指针反过来
channel.write(buffer);
channel.close();
}
}
}
}
public static void main(String[] args) throws IOException {
HttpServer4 server = new HttpServer4();
server.listen(8000);
}
}
自己也可以学着前几篇用ServerSocket写的HttpServer类优化步骤,依葫芦画瓢一样对ServerSocketChannel写的HttpServer类进一步优化,