此文算是《How Tomcat Works》的Scala代码解析版。主要从代码角度来分析Tomcat的结构。使用Scala来进行说明。 采用简单说明+代码注释的方式来描述,代码也尽量简单化,做到以最少的文字来进行表述。
import java.net.ServerSocket import java.net.InetAddress import java.io.File /** * Created with IntelliJ IDEA. * User: Ivan * Date: 12-11-24 * Time: 上午10:41 */ //静态服务器类 class HttpServer { var shutdown = false //核心方法,接受请求,返回响应 def await() { val port = 8080 val serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1")) while (!shutdown) { try { val socket = serverSocket.accept() val input = socket.getInputStream() val output = socket.getOutputStream() //根据请求构造Request,获取资源文件 val request: Request = new Request(input) request.parse() //返回资源文件内容 val response: Response = new Response(output) response.request = request response.sendStaticResource() socket.close() shutdown = request.uri.equals(HttpServer.SHUTDOWN_COMMAND) } catch { case e: Exception => e.printStackTrace() } } } } object HttpServer { val WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot" val SHUTDOWN_COMMAND = "/SHUTDOWN" def main(args: Array[String]) { val server = new HttpServer() server.await() } }
import io.Source import java.io.{IOException, InputStream} /** * Created with IntelliJ IDEA. * User: Ivan * Date: 12-11-24 * Time: 上午11:36 */ //请求类,表示一个请求 //主要功能是从输入流中找到请求的文件名 class Request(input: InputStream) { var uri: String = _ //此处本来使用mkString,但是会死这 //应该是input是流导致的 def parse() { val lines = Source.fromInputStream(input).getLines() if (lines.hasNext) { uri = parseUri(lines.next()) } } /** * 从请求中获得请求的资源链接 * 使用正则表达式组来匹配 * @param requestString * @return */ def parseUri(requestString: String): String = { val pattern = """[^ ]* *([^ ]*) *[\s\S]*""".r val pattern(result) = requestString result } }
import io.Source import java.io.{File, FileInputStream, OutputStream} /** * Created with IntelliJ IDEA. * User: Ivan * Date: 12-11-24 * Time: 上午11:49 */ //相应类,表示一个相应 //主要功能是向响应流中写入结果 class Response(output: OutputStream) { var request: Request = _ //返回访问的文件,或者404 def sendStaticResource() { val file = new File(HttpServer.WEB_ROOT, request.uri) var fis: FileInputStream = null try { if (file.exists()) { fis = new FileInputStream(file) //将文件内容写到响应中 writeToResponse(fis) } else { //文件未找到,写入404信息 output.write(Response.FileNotFoundMessage.getBytes()) } } finally { if (fis != null) fis.close() } } //递归读取文件,写入到响应流 def writeToResponse(fis:FileInputStream){ val ch = fis.read(Response.bytes, 0, Response.BUFFER_SIZE) if(ch != -1){ output.write(Response.bytes, 0, ch) writeToResponse(fis) } } } object Response { val BUFFER_SIZE = 1024 //bytes需要在BUFFER_SIZE后定义,否则大小为0 val bytes = new Array[Byte](Response.BUFFER_SIZE) val FileNotFoundMessage = """HTTP/1.1 404 File Not Found |Content-Type: text/html |Content-Length: 23 | |File Not Found
""" }
Blog URL:http://www.ivanpig.com/blog/?p=485