NanoHTTPD----SimpleWebServer处理请求过程

本文详细介绍了NanoHTTPD服务器如何通过ServerRunnable的run函数启动,创建并执行ClientHandler来处理客户端请求。请求处理过程包括从socket读取数据、解析HTTP头以获取请求信息、调用Server的serve函数生成响应,并最终发送响应结果。重点关注了请求头的解析和SimpleWebServer的serveFile方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

回到ServerRunnable的run函数

   public void run() {
        try {
            httpd.getMyServerSocket().bind(httpd.hostname != null ? new InetSocketAddress(httpd.hostname, httpd
                    .myPort) : new InetSocketAddress(httpd.myPort));//绑定端口地址
            hasBinded = true;
        } catch (IOException e) {
            this.bindException = e;
            return;
        }
        do {
            try {
                final Socket finalAccept = httpd.getMyServerSocket().accept();//接受请求
                if (this.timeout > 0) {
                    finalAccept.setSoTimeout(this.timeout);//连接状态timeout秒没有收到数据的话强制断开客户端
                }
                final InputStream inputStream = finalAccept.getInputStream();
                httpd.asyncRunner.exec(httpd.createClientHandler(finalAccept, inputStream));
                //首先以socket和inputStream参数创建一个ClientHandler,然后调用NanoHTTPD的asyncRunner执行这个handler
            } catch (IOException e) {
                NanoHTTPD.LOG.log(Level.FINE, "Communication with the client broken", e);
            }
        } while (!httpd.getMyServerSocket().isClosed());
    }

当有客户端请求过来的时候,回返回一个Socket.

然后会调用createClientHandler创建一个ClientHandler,ClientHandler是一个Runnable,然后会调用DefaultAsyncRunner的exec执行这个Runnable.

    @Override
    public void exec(ClientHandler clientHandler) {
        ++this.requestCount;
        this.running.add(clientHandler);//添加到运行列表
        createThread(clientHandler).start();//创建一个线程执行这个请求
    }

    protected Thread createThread(ClientHandler clientHandler) {
        Thread t = new Thread(clientHandler);//创建一个线程
        t.setDaemon(true);
        t.setName("NanoHttpd Request Processor (#" + this.requestCount + ")");
        return t;
    }

从这里可以看到,创建了一个线程用来处理这个客户端的请求,这里我们会到ClientHandler的run方法

public void run() {
        OutputStream outputStream = null;
        try {
            outputStream = this.acceptSocket.getOutputStream();//获取输出流,用于发送响应
            ITempFileManager tempFileManager = httpd.getTempFileManagerFactory().create();//临时文件管理
            HTTPSession session = new HTTPSession(httpd, tempFileManager, this.inputStream, outputStream, this
                    .acceptSocket.getInetAddress());//创建一个HTTPSession
            while (!this.acceptSocket.isClosed()) {//未关闭的时候一直执行这条会话
                session.execute();//执行这条会话
            }
        } catch (Exception e) {
            // When the socket is closed by the client,
            // we throw our own SocketException
            // to break the "keep alive" loop above. If
            // the exception was anything other
            // than the expected SocketException OR a
            // SocketTimeoutException, print the
            // stacktrace
            if (!(e instanceof SocketException && "NanoHttpd Shutdown".equals(e.getMessage())) && !(e instanceof SocketTimeoutException)) {
                NanoHTTPD.LOG.log(Level.SEVERE, "Communication with the client broken, or an bug in the handler code", e);
            }
        } finally {
            NanoHTTPD.safeClose(outputStream);
            NanoHTTPD.safeClose(this.inputStream);
            NanoHTTPD.safeClose(this.acceptSocket);
            httpd.asyncRunner.closed(this);
        }
    }
这里主要穿件了一个HTTPSession会话的意思,如果这个socket没有关闭,则一直执行这个会话

public void execute() throws IOException {
        Response r = null;
        try {
            // Read the first 8192 bytes.
            // The full header should fit in here.
            // Apache's default header limit is 8KB.
            // Do NOT assume that a single read will get the entire header
            // at once!
            byte[] buf = new byte[HTTPSession.BUFSIZE];
            this.splitbyte = 0;
            this.rlen = 0;

            int read = -1;
            this.inputStream.mark(HTTPSession.BUFSIZE);//记当前位置,并保证在mark以后最多可以读取readlimit字节数据,mark标记仍有效
            try {
                read = this.inputStream.read(buf, 0, HTTPSession.BUFSIZE);//读取请求数据
            } catch (SSLException e) {
                throw e;
            } catch (IOException e) {
                NanoHTTPD.safeClose(this.inputStream);
                NanoHTTPD.safeClose(this.outputStream);
                throw new SocketException("NanoHttpd Shutdown");
            }
            if (read == -1) {
                // socket was been closed
                NanoHTTPD.safeClose(this.inputStream);
                NanoHTTPD.safeClose(this.outputStream);
                throw new SocketException("NanoHttpd Shutdown");
            }
            while (read > 0) {
                this.rlen += read;
                this.splitbyte = findHeaderEnd(buf, this.rlen);//找到header结束位置
                if (this.splitbyte > 0) {
                    break;
                }
                read = this.inputStream.read(buf, this.rlen, HTTPSession.BUFSIZE - this.rlen);//没有读到数据,则继续读
            }

            if (this.splitbyte < this.rlen) {//header头的数据小于当前读到的数据
                this.inputStream.reset();//重设输入流
                this.inputStream.skip(this.splitbyte);//忽略读到的头数据
            }

            this.parms = new HashMap<String, List<String>>();
            if (null == this.headers) {
                this.headers = new HashMap<String, String>();
            } else {
                this.headers.clear();
            }

            // Create a BufferedReader for parsing the header.创建一个BufferedReader,用来解析头
            BufferedReader hin = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(buf, 0, this.rlen)));

            // Decode the header into parms and header java properties
            Map<String, String> pre = new HashMap<String, String>();
            decodeHeader(hin, pre, this.parms, this.headers);//解析头

            if (null != this.remoteIp) {//添加ip
                this.headers.put("remote-addr", this.remoteIp);
                this.headers.put("http-client-ip", this.remoteIp);
            }

            this.method = Method.lookup(pre.get("method"));
            if (this.method == null) {
                throw new ResponseException(Status.BAD_REQUEST, "BAD REQUEST: Syntax error. HTTP verb " + pre.get("method") + " unhandled.");
            }

            this.uri = pre.get("uri");

            this.cookies = new CookieHandler(this.headers);//处理Cookie

            String connection = this.headers.get("connection");//是否保持连接
            boolean keepAlive = "HTTP/1.1".equals(protocolVersion) && (connection == null || !connection.matches("(?i).*close.*"));

            // Ok, now do the serve()

            // TODO: long body_size = getBodySize();
            // TODO: long pos_before_serve = this.inputStream.totalRead()
            // (requires implementation for totalRead())
            r = httpd.serve(this);//调用server处理这个会话,返回响应
            // TODO: this.inputStream.skip(body_size -
            // (this.inputStream.totalRead() - pos_before_serve))

            if (r == null) {
                throw new ResponseException(Status.INTERNAL_ERROR, "SERVER INTERNAL ERROR: Serve() returned a null response.");
            } else {
                String acceptEncoding = this.headers.get("accept-encoding");//获取浏览器支持的编码类型
                this.cookies.unloadQueue(r);//响应头添加cookie
                r.setRequestMethod(this.method);//设置请求方法
                r.setGzipEncoding(httpd.useGzipWhenAccepted(r)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值