NIONIO实现HTTP服务器
Posted 喜欢天文
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NIONIO实现HTTP服务器相关的知识,希望对你有一定的参考价值。
-
NIO 实现的HTTP服务器 -
该版本只处理了静态资源,如需要处理动态资源可参考上一篇文章 -
本篇文章的代码注释比较少,详细的NIO的工作流程可参考
/**
* NIO实现HTTP服务器
*
* @author futao
* @date 2020/7/10
*/
@Slf4j
public class NioHttpServer {
private static final ByteBuffer READ_BUFFER = ByteBuffer.allocate(1024 * 4);
/**
* 静态资源路径
*/
private static final String STATIC_RESOURCE_PATH = System.getProperty("user.dir") + "/practice/src/main/resources/pages/";
/**
* 响应的基础信息
*/
public static final String BASIC_RESPONSE = "HTTP/1.1 200 OK\r\n" +
"Content-Type: text/html;charset=utf-8\r\n" +
"Vary: Accept-Encoding\r\n";
/**
* 回车换行符
*/
private static final String carriageReturn = "\r\n";
public void start() {
try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress("localhost", Constants.SERVER_PORT));
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
int eventCountTriggered = selector.select();
if (eventCountTriggered == 0) {
continue;
}
Set<SelectionKey> selectionKeys = selector.selectedKeys();
for (SelectionKey selectionKey : selectionKeys) {
handleSelectKey(selectionKey, selector);
}
selectionKeys.clear();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void handleSelectKey(SelectionKey selectionKey, Selector selector) {
if (selectionKey.isAcceptable()) {
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
try {
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
log.debug("客户端[{}]接入", socketChannel.socket().getPort());
} catch (IOException e) {
e.printStackTrace();
}
} else if (selectionKey.isReadable()) {
READ_BUFFER.clear();
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
try {
while (socketChannel.read(READ_BUFFER) > 0) {
}
READ_BUFFER.flip();
String requestMessage = String.valueOf(Constants.CHARSET.decode(READ_BUFFER));
log.info("接收到浏览器发来的数据:\n{} === request print end...", requestMessage);
if (StringUtils.isBlank(requestMessage)) {
selectionKey.cancel();
selector.wakeup();
}
String requestUri = NioHttpServer.getRequestUri(requestMessage);
staticHandler(requestUri, socketChannel);
selectionKey.cancel();
selector.wakeup();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 获取请求的资源地址
*
* @param request
* @return
*/
private static String getRequestUri(String request) {
//GET /index.html HTTP/1.1
int firstBlank = request.indexOf(" ");
String excludeMethod = request.substring(firstBlank + 2);
return excludeMethod.substring(0, excludeMethod.indexOf(" "));
}
/**
* 静态资源处理器
*
* @return
*/
public boolean staticHandler(String page, SocketChannel socketChannel) throws IOException {
//资源的绝对路径
String filePath = NioHttpServer.STATIC_RESOURCE_PATH + page;
boolean fileExist = false;
File file = new File(filePath);
if (file.exists() && file.isFile()) {
log.debug("静态资源[{}]存在", page);
fileExist = true;
//读取文件内容
byte[] bytes = Files.readAllBytes(Paths.get(filePath));
ByteBuffer buffer = ByteBuffer.allocate(4 * 1024);
buffer.put(BASIC_RESPONSE.getBytes(Constants.CHARSET));
buffer.put(("Server: futaoServerBaseNIO/1.1" + NioHttpServer.carriageReturn).getBytes(Constants.CHARSET));
buffer.put(("content-length: " + bytes.length + NioHttpServer.carriageReturn).getBytes(Constants.CHARSET));
buffer.put(NioHttpServer.carriageReturn.getBytes(Constants.CHARSET));
buffer.put(bytes);
buffer.flip();
while (buffer.hasRemaining()) {
socketChannel.write(buffer);
}
}
return fileExist;
}
public static void main(String[] args) {
new NioHttpServer().start();
}
}
-
测试
# 源代码
-
https://github.com/FutaoSmile/learn-IO/tree/master/practice/src/main/java/com/futao/practice/chatroom/nio/httpserver
# 系列文章
欢迎在评论区留下你看文章时的思考,及时说出,有助于加深记忆和理解,还能和像你一样也喜欢这个话题的读者相遇~
以上是关于NIONIO实现HTTP服务器的主要内容,如果未能解决你的问题,请参考以下文章