【NIO】NIO实现HTTP服务器

简介: 【NIO】NIO实现HTTP服务器
  • NIO 实现的HTTP服务器

/**
 * 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();
    }
}


  • 测试

image.png

image.png

image.png

# 源代码



# 系列文章


相关文章
|
2天前
|
缓存 负载均衡 监控
HTTP代理服务器在网络安全中的重要性
随着科技和互联网的发展,HTTP代理IP中的代理服务器在企业业务中扮演重要角色。其主要作用包括:保护用户信息、访问控制、缓存内容、负载均衡、日志记录和协议转换,从而在网络管理、性能优化和安全性方面发挥关键作用。
16 2
|
1月前
|
搜索推荐 安全 网络安全
服务器支持HTTPS的时机和条件
【10月更文挑战第23天】服务器支持HTTPS的时机和条件
23 5
|
2月前
使用Netty实现文件传输的HTTP服务器和客户端
本文通过详细的代码示例,展示了如何使用Netty框架实现一个文件传输的HTTP服务器和客户端,包括服务端的文件处理和客户端的文件请求与接收。
75 1
使用Netty实现文件传输的HTTP服务器和客户端
|
1月前
|
存储 Oracle 关系型数据库
oracle服务器存储过程中调用http
通过配置权限、创建和调用存储过程,您可以在Oracle数据库中使用UTL_HTTP包发起HTTP请求。这使得Oracle存储过程可以与外部HTTP服务进行交互,从而实现更复杂的数据处理和集成。在实际应用中,根据具体需求调整请求类型和错误处理逻辑,以确保系统的稳定性和可靠性。
63 0
|
3月前
HAProxy的高级配置选项-配置haproxy支持https协议及服务器动态上下线
文章介绍了如何配置HAProxy以支持HTTPS协议和实现服务器的动态上下线。
170 8
HAProxy的高级配置选项-配置haproxy支持https协议及服务器动态上下线
|
3月前
|
开发者
HTTP状态码是由网页服务器返回的三位数字响应代码,用于表示请求的处理结果和状态
HTTP状态码是由网页服务器返回的三位数字响应代码,用于表示请求的处理结果和状态
39 1
|
4月前
|
移动开发 网络协议 编译器
实战案例3:C语言实现的HTTP服务器
实战案例3:C语言实现的HTTP服务器
286 0
|
Web App开发
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
TCP洪水攻击(SYN Flood)的诊断和处理 Posted by  海涛  on 2013 年 7 月 11 日 Tweet1 ​1. SYN Flood介绍 前段时间网站被攻击多次,其中最猛烈的就是TCP洪水攻击,即SYN Flood。
1011 0
|
Web App开发 前端开发 Java
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
线程的状态有:new、runnable、running、waiting、timed_waiting、blocked、dead 当执行new Thread(Runnabler)后,新创建出来的线程处于new状态,这种线程不可能执行 当执行thread.start()后,线程处于runnable状态,这种情况下只要得到CPU,就可以开始执行了。
738 0
|
Web App开发 前端开发 Java
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
ZooKeeper 保证了数据的强一致性,  zk集群中任意节点(一个zkServer)上的相同znode下的数据一定是相同的。
807 0
下一篇
DataWorks