一、Socket
Socket是网络编程接口(API),使得开发者可以方便地使用TCP\IP协议进行数据的传输,其客户端与服务端的交互流程为:
二、Http协议
Web应用程序主要使用HTTP协议,但HTTP协议本身存在两个问题:无状态和内容的文本表示。对于前者来说,没有记录多个请求之间的关系,而对后者来讲,如果使用Java来编程,需要进行文本和Java类型的转换.
三、Servlet
Java针对Web提出了Servlet规范,即提供了Java与HTTP协议沟通的接口,这意味着Java可以以直观的面向对象的抽象方式编写HTTP服务端代码;Servlet接受请求对象,检查其中的数据,执行适当的后台逻辑,然后向客户返回响应。
(1). 提供Java使用HTTP的方法;
(2). 提供了会话机制,解决无状态问题;
(3). 负责包装的请求对象,无须开发人员解析传入的HTTP请求;
四、Tomcat
Tomcat是实现Servlet规范的容器,单线程处理简单示例:
Http服务类代码
public class HttpServer1 { /** WEB_ROOT is the directory where our HTML and other files reside. * For this package, WEB_ROOT is the "webroot" directory under the working * directory. * The working directory is the location in the file system * from where the java command was invoked. */ // shutdown command private static final String SHUTDOWN_COMMAND = "/SHUTDOWN"; // the shutdown command received private boolean shutdown = false; public static void main(String[] args) { HttpServer1 server = new HttpServer1(); server.await(); } public void await() { ServerSocket serverSocket = null; int port = 8080; try { serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1")); } catch (IOException e) { e.printStackTrace(); System.exit(1); } // Loop waiting for a request while (!shutdown) { Socket socket = null; InputStream input = null; OutputStream output = null; try { socket = serverSocket.accept(); input = socket.getInputStream(); output = socket.getOutputStream(); // create Request object and parse Request request = new Request(input); request.parse(); // create Response object Response response = new Response(output); response.setRequest(request); // check if this is a request for a servlet or a static resource // a request for a servlet begins with "/servlet/" if (request.getUri().startsWith("/servlet/")) { ServletProcessor1 processor = new ServletProcessor1(); processor.process(request, response); } else { StaticResourceProcessor processor = new StaticResourceProcessor(); processor.process(request, response); } // Close the socket socket.close(); //check if the previous URI is a shutdown command shutdown = request.getUri().equals(SHUTDOWN_COMMAND); } catch (Exception e) { e.printStackTrace(); System.exit(1); } } } }
Servlet处理类代码:
public class ServletProcessor1 { public void process(Request request, Response response) { String uri = request.getUri(); String servletName = uri.substring(uri.lastIndexOf("/") + 1); URLClassLoader loader = null; try { // create a URLClassLoader URL[] urls = new URL[1]; URLStreamHandler streamHandler = null; File classPath = new File(Constants.WEB_ROOT); // the forming of repository is taken from the createClassLoader method in // org.apache.catalina.startup.ClassLoaderFactory String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString() ; // the code for forming the URL is taken from the addRepository method in // org.apache.catalina.loader.StandardClassLoader class. urls[0] = new URL(null, repository, streamHandler); loader = new URLClassLoader(urls); } catch (IOException e) { System.out.println(e.toString() ); } Class myClass = null; try { myClass = loader.loadClass(servletName); } catch (ClassNotFoundException e) { System.out.println(e.toString()); } Servlet servlet = null; try { servlet = (Servlet) myClass.newInstance(); servlet.service((ServletRequest) request, (ServletResponse) response); } catch (Exception e) { System.out.println(e.toString()); } catch (Throwable e) { System.out.println(e.toString()); } } }
多线程:
public final class Bootstrap { public static void main(String[] args) { HttpConnector connector = new HttpConnector(); connector.start(); } }
public class HttpConnector implements Runnable { boolean stopped; private String scheme = "http"; public String getScheme() { return scheme; } public void run() { ServerSocket serverSocket = null; int port = 8080; try { serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1")); } catch (IOException e) { e.printStackTrace(); System.exit(1); } while (!stopped) { // Accept the next incoming connection from the server socket Socket socket = null; try { socket = serverSocket.accept(); } catch (Exception e) { continue; } // Hand this socket off to an HttpProcessor HttpProcessor processor = new HttpProcessor(this); processor.process(socket); } } public void start() { Thread thread = new Thread(this); thread.start(); } }
public class HttpProcessor { public HttpProcessor(HttpConnector connector) { this.connector = connector; } /** * The HttpConnector with which this processor is associated. */ private HttpConnector connector = null; private HttpRequest request; private HttpRequestLine requestLine = new HttpRequestLine(); private HttpResponse response; protected String method = null; protected String queryString = null; /** * The string manager for this package. */ protected StringManager sm = StringManager.getManager("ex03.pyrmont.connector.http"); public void process(Socket socket) { SocketInputStream input = null; OutputStream output = null; try { input = new SocketInputStream(socket.getInputStream(), 2048); output = socket.getOutputStream(); // create HttpRequest object and parse request = new HttpRequest(input); // create HttpResponse object response = new HttpResponse(output); response.setRequest(request); response.setHeader("Server", "Pyrmont Servlet Container"); parseRequest(input, output); parseHeaders(input); //check if this is a request for a servlet or a static resource //a request for a servlet begins with "/servlet/" if (request.getRequestURI().startsWith("/servlet/")) { ServletProcessor processor = new ServletProcessor(); processor.process(request, response); } else { StaticResourceProcessor processor = new StaticResourceProcessor(); processor.process(request, response); } // Close the socket socket.close(); // no shutdown for this application } catch (Exception e) { e.printStackTrace(); } } /** * This method is the simplified version of the similar method in * org.apache.catalina.connector.http.HttpProcessor. * However, this method only parses some "easy" headers, such as * "cookie", "content-length", and "content-type", and ignore other headers. * @param input The input stream connected to our socket * * @exception IOException if an input/output error occurs * @exception ServletException if a parsing error occurs */ private void parseHeaders(SocketInputStream input) throws IOException, ServletException { while (true) { HttpHeader header = new HttpHeader();; // Read the next header input.readHeader(header); if (header.nameEnd == 0) { if (header.valueEnd == 0) { return; } else { throw new ServletException (sm.getString("httpProcessor.parseHeaders.colon")); } } String name = new String(header.name, 0, header.nameEnd); String value = new String(header.value, 0, header.valueEnd); request.addHeader(name, value); // do something for some headers, ignore others. if (name.equals("cookie")) { Cookie cookies[] = RequestUtil.parseCookieHeader(value); for (int i = 0; i < cookies.length; i++) { if (cookies[i].getName().equals("jsessionid")) { // Override anything requested in the URL if (!request.isRequestedSessionIdFromCookie()) { // Accept only the first session id cookie request.setRequestedSessionId(cookies[i].getValue()); request.setRequestedSessionCookie(true); request.setRequestedSessionURL(false); } } request.addCookie(cookies[i]); } } else if (name.equals("content-length")) { int n = -1; try { n = Integer.parseInt(value); } catch (Exception e) { throw new ServletException(sm.getString("httpProcessor.parseHeaders.contentLength")); } request.setContentLength(n); } else if (name.equals("content-type")) { request.setContentType(value); } } //end while } private void parseRequest(SocketInputStream input, OutputStream output) throws IOException, ServletException { // Parse the incoming request line input.readRequestLine(requestLine); String method = new String(requestLine.method, 0, requestLine.methodEnd); String uri = null; String protocol = new String(requestLine.protocol, 0, requestLine.protocolEnd); // Validate the incoming request line if (method.length() < 1) { throw new ServletException("Missing HTTP request method"); } else if (requestLine.uriEnd < 1) { throw new ServletException("Missing HTTP request URI"); } // Parse any query parameters out of the request URI int question = requestLine.indexOf("?"); if (question >= 0) { request.setQueryString(new String(requestLine.uri, question + 1, requestLine.uriEnd - question - 1)); uri = new String(requestLine.uri, 0, question); } else { request.setQueryString(null); uri = new String(requestLine.uri, 0, requestLine.uriEnd); } // Checking for an absolute URI (with the HTTP protocol) if (!uri.startsWith("/")) { int pos = uri.indexOf("://"); // Parsing out protocol and host name if (pos != -1) { pos = uri.indexOf(‘/‘, pos + 3); if (pos == -1) { uri = ""; } else { uri = uri.substring(pos); } } } // Parse any requested session ID out of the request URI String match = ";jsessionid="; int semicolon = uri.indexOf(match); if (semicolon >= 0) { String rest = uri.substring(semicolon + match.length()); int semicolon2 = rest.indexOf(‘;‘); if (semicolon2 >= 0) { request.setRequestedSessionId(rest.substring(0, semicolon2)); rest = rest.substring(semicolon2); } else { request.setRequestedSessionId(rest); rest = ""; } request.setRequestedSessionURL(true); uri = uri.substring(0, semicolon) + rest; } else { request.setRequestedSessionId(null); request.setRequestedSessionURL(false); } // Normalize URI (using String operations at the moment) String normalizedUri = normalize(uri); // Set the corresponding request properties ((HttpRequest) request).setMethod(method); request.setProtocol(protocol); if (normalizedUri != null) { ((HttpRequest) request).setRequestURI(normalizedUri); } else { ((HttpRequest) request).setRequestURI(uri); } if (normalizedUri == null) { throw new ServletException("Invalid URI: " + uri + "‘"); } } /** * Return a context-relative path, beginning with a "/", that represents * the canonical version of the specified path after ".." and "." elements * are resolved out. If the specified path attempts to go outside the * boundaries of the current context (i.e. too many ".." path elements * are present), return <code>null</code> instead. * * @param path Path to be normalized */ protected String normalize(String path) { if (path == null) return null; // Create a place for the normalized path String normalized = path; // Normalize "/%7E" and "/%7e" at the beginning to "/~" if (normalized.startsWith("/%7E") || normalized.startsWith("/%7e")) normalized = "/~" + normalized.substring(4); // Prevent encoding ‘%‘, ‘/‘, ‘.‘ and ‘\‘, which are special reserved // characters if ((normalized.indexOf("%25") >= 0) || (normalized.indexOf("%2F") >= 0) || (normalized.indexOf("%2E") >= 0) || (normalized.indexOf("%5C") >= 0) || (normalized.indexOf("%2f") >= 0) || (normalized.indexOf("%2e") >= 0) || (normalized.indexOf("%5c") >= 0)) { return null; } if (normalized.equals("/.")) return "/"; // Normalize the slashes and add leading slash if necessary if (normalized.indexOf(‘\\‘) >= 0) normalized = normalized.replace(‘\\‘, ‘/‘); if (!normalized.startsWith("/")) normalized = "/" + normalized; // Resolve occurrences of "//" in the normalized path while (true) { int index = normalized.indexOf("//"); if (index < 0) break; normalized = normalized.substring(0, index) + normalized.substring(index + 1); } // Resolve occurrences of "/./" in the normalized path while (true) { int index = normalized.indexOf("/./"); if (index < 0) break; normalized = normalized.substring(0, index) + normalized.substring(index + 2); } // Resolve occurrences of "/../" in the normalized path while (true) { int index = normalized.indexOf("/../"); if (index < 0) break; if (index == 0) return (null); // Trying to go outside our context int index2 = normalized.lastIndexOf(‘/‘, index - 1); normalized = normalized.substring(0, index2) + normalized.substring(index + 3); } // Declare occurrences of "/..." (three or more dots) to be invalid // (on some Windows platforms this walks the directory tree!!!) if (normalized.indexOf("/...") >= 0) return (null); // Return the normalized path that we have completed return (normalized); } }
实际上,Tomcat会建立线程池来响应请求,Tomcat的连接数配置可参考:http://www.cnblogs.com/baibaluo/archive/2011/08/23/2150305.html
时间: 2024-11-05 17:44:46