回到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)