tomcat探究三使用连接器--参考tomcat4
说明
连接器就是管理连接的,可以理解为连接池–现在都是使用这个;只不过这里没用到池
Bootstrap:启动程序–就是main方法入口
HttpConnector–连接器,管理请求的
HttpProcessor–请求处理
HttpHeader–存储请求头部分的信息,暂时没用到
HttpRequestLine–存储请求行信息
SocketInputStream–处理输入流
HttpRequest–请求对象
HttpRequestFacade – 提供外部操作请求对象
HttpResponse–响应对象
HttpResponseFacade–提供外部操作响应对象
Servlet–定义servlet模板
ServletProcessor–加载servlet容器
静态处理的就不列出来了,可以参考 探究二
大概图解
启动程序
Bootstrap
/**
* 启动程序
*/
public class Bootstrap {
public static void main(String[] args) {
HttpConnector httpConnector = new HttpConnector();
httpConnector.start();
}
}
连接器相关
HttpConnector
/**
* 连接器
* 负责创建连接
*/
public class HttpConnector implements Runnable{
boolean stoped = false;
private String scheme = "http";
public String gtScheme() {
return scheme;
}
@Override
public void run() {
ServerSocket serverSocket = null;
int port = 8080;
try {
serverSocket = new ServerSocket(port);
} catch (Exception e) {
e.printStackTrace();
}
while(!stoped) {
Socket socket = null;
try {
socket = serverSocket.accept();
} catch (Exception e) {
e.printStackTrace();
continue;
}
HttpProcessor processor = new HttpProcessor();
processor.process(socket);
}
}
public void start() {
new Thread(this).start();
}
}
请求处理相关
HttpProcessor
/**
* 处理连接
*/
public class HttpProcessor {
public void process(Socket socket) {
InputStream in = null;
OutputStream out = null;
HttpRequest request = null;
HttpResponse response = null;
try {
in = socket.getInputStream();
out = socket.getOutputStream();
if(in.available() <= 0) {
return;
}
request = new HttpRequest(in);
response = new HttpResponse(out);
SocketInputStream stream = new SocketInputStream(in, 2048);
//处理请求
parseRequest(stream, request);
parseHeaders(in);
if(request.getUri().startsWith("/servlet/")) {
ServletProcessor processor = new ServletProcessor();
HttpRequestFacade httpRequestFacade = new HttpRequestFacade(request);
HttpResponseFacade httpResponseFacade = new HttpResponseFacade(response);
processor.process(httpRequestFacade,httpResponseFacade);
}else {
StaticResourceProcessor processor = new StaticResourceProcessor();
processor.process(request,response);
}
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private void parseHeaders(InputStream in) {
// TODO Auto-generated method stub
//这个暂时不做处理
}
private void parseRequest(SocketInputStream in,HttpRequest request) throws Exception {
//对输入流进行解析
HttpRequestLine requestLine = new HttpRequestLine();
in.readRequestLine(requestLine);
String method = new String(requestLine.method, 0, requestLine.methodEnd);
String protocol = new String(requestLine.protocol, 0,requestLine.protocolEnd);
String uri = new String(requestLine.uri, 0, requestLine.uriEnd);
request.setUri(uri);
request.setMethod(method);
request.setProtocol(protocol);
}
}
HttpHeader – 从tomcat复制过来
/**
* HTTP header enum type.
*
* @author Remy Maucherat
* @version $Revision: 466595 $ $Date: 2006-10-21 23:24:41 +0100 (Sat, 21 Oct 2006) $
*/
final class HttpHeader {
// -------------------------------------------------------------- Constants
public static final int INITIAL_NAME_SIZE = 32;
public static final int INITIAL_VALUE_SIZE = 64;
public static final int MAX_NAME_SIZE = 128;
public static final int MAX_VALUE_SIZE = 4096;
// ----------------------------------------------------------- Constructors
public HttpHeader() {
this(new char[INITIAL_NAME_SIZE], 0, new char[INITIAL_VALUE_SIZE], 0);
}
public HttpHeader(char[] name, int nameEnd, char[] value, int valueEnd) {
this.name = name;
this.nameEnd = nameEnd;
this.value = value;
this.valueEnd = valueEnd;
}
public HttpHeader(String name, String value) {
this.name = name.toLowerCase().toCharArray();
this.nameEnd = name.length();
this.value = value.toCharArray();
this.valueEnd = value.length();
}
// ----------------------------------------------------- Instance Variables
public char[] name;
public int nameEnd;
public char[] value;
public int valueEnd;
protected int hashCode = 0;
// ------------------------------------------------------------- Properties
// --------------------------------------------------------- Public Methods
/**
* Release all object references, and initialize instance variables, in
* preparation for reuse of this object.
*/
public void recycle() {
nameEnd = 0;
valueEnd = 0;
hashCode = 0;
}
/**
* Test if the name of the header is equal to the given char array.
* All the characters must already be lower case.
*/
public boolean equals(char[] buf) {
return equals(buf, buf.length);
}
/**
* Test if the name of the header is equal to the given char array.
* All the characters must already be lower case.
*/
public boolean equals(char[] buf, int end) {
if (end != nameEnd)
return false;
for (int i=0; i<end; i++) {
if (buf[i] != name[i])
return false;
}
return true;
}
/**
* Test if the name of the header is equal to the given string.
* The String given must be made of lower case characters.
*/
public boolean equals(String str) {
return equals(str.toCharArray(), str.length());
}
/**
* Test if the value of the header is equal to the given char array.
*/
public boolean valueEquals(char[] buf) {
return valueEquals(buf, buf.length);
}
/**
* Test if the value of the header is equal to the given char array.
*/
public boolean valueEquals(char[] buf, int end) {
if (end != valueEnd)
return false;
for (int i=0; i<end; i++) {
if (buf[i] != value[i])
return false;
}
return true;
}
/**
* Test if the value of the header is equal to the given string.
*/
public boolean valueEquals(String str) {
return valueEquals(str.toCharArray(), str.length());
}
/**
* Test if the value of the header includes the given char array.
*/
public boolean valueIncludes(char[] buf) {
return valueIncludes(buf, buf.length);
}
/**
* Test if the value of the header includes the given char array.
*/
public boolean valueIncludes(char[] buf, int end) {
char firstChar = buf[0];
int pos = 0;
while (pos < valueEnd) {
pos = valueIndexOf(firstChar, pos);
if (pos == -1)
return false;
if ((valueEnd - pos) < end)
return false;
for (int i = 0; i < end; i++) {
if (value[i + pos] != buf[i])
break;
if (i == (end-1))
return true;
}
pos++;
}
return false;
}
/**
* Test if the value of the header includes the given string.
*/
public boolean valueIncludes(String str) {
return valueIncludes(str.toCharArray(), str.length());
}
/**
* Returns the index of a character in the value.
*/
public int valueIndexOf(char c, int start) {
for (int i=start; i<valueEnd; i++) {
if (value[i] == c)
return i;
}
return -1;
}
/**
* Test if the name of the header is equal to the given header.
* All the characters in the name must already be lower case.
*/
public boolean equals(HttpHeader header) {
return (equals(header.name, header.nameEnd));
}
/**
* Test if the name and value of the header is equal to the given header.
* All the characters in the name must already be lower case.
*/
public boolean headerEquals(HttpHeader header) {
return (equals(header.name, header.nameEnd))
&& (valueEquals(header.value, header.valueEnd));
}
// --------------------------------------------------------- Object Methods
/**
* Return hash code. The hash code of the HttpHeader object is the same
* as returned by new String(name, 0, nameEnd).hashCode().
*/
public int hashCode() {
int h = hashCode;
if (h == 0) {
int off = 0;
char val[] = name;
int len = nameEnd;
for (int i = 0; i < len; i++)
h = 31*h + val[off++];
hashCode = h;
}
return h;
}
public boolean equals(Object obj) {
if (obj instanceof String) {
return equals(((String) obj).toLowerCase());
} else if (obj instanceof HttpHeader) {
return equals((HttpHeader) obj);
}
return false;
}
}
HttpRequestLine – 从tomcat4复制过来
final class HttpRequestLine {
public static final int INITIAL_METHOD_SIZE = 8;
public static final int INITIAL_URI_SIZE = 64;
public static final int INITIAL_PROTOCOL_SIZE = 8;
public static final int MAX_METHOD_SIZE = 1024;
public static final int MAX_URI_SIZE = 32768;
public static final int MAX_PROTOCOL_SIZE = 1024;
// ----------------------------------------------------------- Constructors
public HttpRequestLine() {
this(new char[INITIAL_METHOD_SIZE], 0, new char[INITIAL_URI_SIZE], 0,
new char[INITIAL_PROTOCOL_SIZE], 0);
}
public HttpRequestLine(char[] method, int methodEnd,
char[] uri, int uriEnd,
char[] protocol, int protocolEnd) {
this.method = method;
this.methodEnd = methodEnd;
this.uri = uri;
this.uriEnd = uriEnd;
this.protocol = protocol;
this.protocolEnd = protocolEnd;
}
// ----------------------------------------------------- Instance Variables
public char[] method;
public int methodEnd;
public char[] uri;
public int uriEnd;
public char[] protocol;
public int protocolEnd;
// ------------------------------------------------------------- Properties
// --------------------------------------------------------- Public Methods
/**
* Release all object references, and initialize instance variables, in
* preparation for reuse of this object.
*/
public void recycle() {
methodEnd = 0;
uriEnd = 0;
protocolEnd = 0;
}
/**
* Test if the uri includes the given char array.
*/
public int indexOf(char[] buf) {
return indexOf(buf, buf.length);
}
/**
* Test if the value of the header includes the given char array.
*/
public int indexOf(char[] buf, int end) {
char firstChar = buf[0];
int pos = 0;
while (pos < uriEnd) {
pos = indexOf(firstChar, pos);
if (pos == -1)
return -1;
if ((uriEnd - pos) < end)
return -1;
for (int i = 0; i < end; i++) {
if (uri[i + pos] != buf[i])
break;
if (i == (end-1))
return pos;
}
pos++;
}
return -1;
}
/**
* Test if the value of the header includes the given string.
*/
public int indexOf(String str) {
return indexOf(str.toCharArray(), str.length());
}
/**
* Returns the index of a character in the value.
*/
public int indexOf(char c, int start) {
for (int i=start; i<uriEnd; i++) {
if (uri[i] == c)
return i;
}
return -1;
}
// --------------------------------------------------------- Object Methods
public int hashCode() {
// FIXME
return 0;
}
public boolean equals(Object obj) {
return false;
}
}
SocketInputStream --从tomcat复制过来
public class SocketInputStream extends InputStream {
// -------------------------------------------------------------- Constants
/**
* CR.
*/
private static final byte CR = (byte) '\r';
/**
* LF.
*/
private static final byte LF = (byte) '\n';
/**
* SP.
*/
private static final byte SP = (byte) ' ';
/**
* HT.
*/
private static final byte HT = (byte) '\t';
/**
* COLON.
*/
private static final byte COLON = (byte) ':';
/**
* Lower case offset.
*/
private static final int LC_OFFSET = 'A' - 'a';
/**
* Internal buffer.
*/
protected byte buf[];
/**
* Last valid byte.
*/
protected int count;
/**
* Position in the buffer.
*/
protected int pos;
/**
* Underlying input stream.
*/
protected InputStream is;
// ----------------------------------------------------------- Constructors
/**
* Construct a servlet input stream associated with the specified socket
* input.
*
* @param is socket input stream
* @param bufferSize size of the internal buffer
*/
public SocketInputStream(InputStream is, int bufferSize) {
this.is = is;
buf = new byte[bufferSize];
}
// -------------------------------------------------------------- Variables
// ----------------------------------------------------- Instance Variables
// --------------------------------------------------------- Public Methods
/**
* Read the request line, and copies it to the given buffer. This
* function is meant to be used during the HTTP request header parsing.
* Do NOT attempt to read the request body using it.
*
* @param requestLine Request line object
* @throws IOException If an exception occurs during the underlying socket
* read operations, or if the given buffer is not big enough to accomodate
* the whole line.
*/
public void readRequestLine(HttpRequestLine requestLine)
throws IOException {
// Recycling check
if (requestLine.methodEnd != 0)
requestLine.recycle();
// Checking for a blank line
int chr = 0;
do { // Skipping CR or LF
try {
chr = read();
} catch (IOException e) {
chr = -1;
}
} while ((chr == CR) || (chr == LF));
if (chr == -1)
throw new EOFException
("requestStream.readline.error");
pos--;
// Reading the method name
int maxRead = requestLine.method.length;
int readCount = 0;
boolean space = false;
//读取请求方法 GET或者POST
while (!space) {
// if the buffer is full, extend it
//判断是否超出默认的数组大小 --用来存储请求方法名 [G,E,T]
if (readCount >= maxRead) {
if ((2 * maxRead) <= HttpRequestLine.MAX_METHOD_SIZE) {
char[] newBuffer = new char[2 * maxRead];
System.arraycopy(requestLine.method, 0, newBuffer, 0,
maxRead);
requestLine.method = newBuffer;
maxRead = requestLine.method.length;
} else {
throw new IOException
("requestStream.readline.toolong");
}
}
// We're at the end of the internal buffer
//判断当前读是否超出最大下标
if (pos >= count) {
int val = read();
if (val == -1) {
throw new IOException
("requestStream.readline.error");
}
pos = 0;
}
//根据HTTP协议的第一行, 请求方法后面是一个空格,因此当遇到第一个空格时,则跳出循环
if (buf[pos] == SP) {
space = true;
}
requestLine.method[readCount] = (char) buf[pos];
readCount++;
pos++;
}
requestLine.methodEnd = readCount - 1;
// Reading URI
maxRead = requestLine.uri.length;
readCount = 0;
space = false;
boolean eol = false;
//获取uri 同上面获取请求方法一样
while (!space) {
// if the buffer is full, extend it
if (readCount >= maxRead) {
if ((2 * maxRead) <= HttpRequestLine.MAX_URI_SIZE) {
char[] newBuffer = new char[2 * maxRead];
System.arraycopy(requestLine.uri, 0, newBuffer, 0,
maxRead);
requestLine.uri = newBuffer;
maxRead = requestLine.uri.length;
} else {
throw new IOException
("requestStream.readline.toolong");
}
}
// We're at the end of the internal buffer
if (pos >= count) {
int val = read();
if (val == -1)
throw new IOException
("requestStream.readline.error");
pos = 0;
}
if (buf[pos] == SP) {
space = true;
} else if ((buf[pos] == CR) || (buf[pos] == LF)) {
// HTTP/0.9 style request
eol = true;
space = true;
}
requestLine.uri[readCount] = (char) buf[pos];
readCount++;
pos++;
}
requestLine.uriEnd = readCount - 1;
// Reading protocol
maxRead = requestLine.protocol.length;
readCount = 0;
//获取协议 都是一样的逻辑
while (!eol) {
// if the buffer is full, extend it
if (readCount >= maxRead) {
if ((2 * maxRead) <= HttpRequestLine.MAX_PROTOCOL_SIZE) {
char[] newBuffer = new char[2 * maxRead];
System.arraycopy(requestLine.protocol, 0, newBuffer, 0,
maxRead);
requestLine.protocol = newBuffer;
maxRead = requestLine.protocol.length;
} else {
throw new IOException
("requestStream.readline.toolong");
}
}
// We're at the end of the internal buffer
if (pos >= count) {
// Copying part (or all) of the internal buffer to the line
// buffer
int val = read();
if (val == -1)
throw new IOException
("requestStream.readline.error");
pos = 0;
}
if (buf[pos] == CR) {
// Skip CR.
} else if (buf[pos] == LF) {
eol = true;
} else {
requestLine.protocol[readCount] = (char) buf[pos];
readCount++;
}
pos++;
}
requestLine.protocolEnd = readCount;
}
/**
* Read a header, and copies it to the given buffer. This
* function is meant to be used during the HTTP request header parsing.
* Do NOT attempt to read the request body using it.
*
* @param header Request header
* @throws IOException If an exception occurs during the underlying socket
* read operations, or if the given buffer is not big enough to accomodate
* the whole line.
*/
public void readHeader(HttpHeader header)
throws IOException {
// Recycling check
if (header.nameEnd != 0)
header.recycle();
// Checking for a blank line
int chr = read();
if ((chr == CR) || (chr == LF)) { // Skipping CR
if (chr == CR)
read(); // Skipping LF
header.nameEnd = 0;
header.valueEnd = 0;
return;
} else {
pos--;
}
// Reading the header name
int maxRead = header.name.length;
int readCount = 0;
boolean colon = false;
while (!colon) {
// if the buffer is full, extend it
if (readCount >= maxRead) {
if ((2 * maxRead) <= HttpHeader.MAX_NAME_SIZE) {
char[] newBuffer = new char[2 * maxRead];
System.arraycopy(header.name, 0, newBuffer, 0, maxRead);
header.name = newBuffer;
maxRead = header.name.length;
} else {
throw new IOException
("requestStream.readline.toolong");
}
}
// We're at the end of the internal buffer
if (pos >= count) {
int val = read();
if (val == -1) {
throw new IOException
("requestStream.readline.error");
}
pos = 0;
}
if (buf[pos] == COLON) {
colon = true;
}
char val = (char) buf[pos];
if ((val >= 'A') && (val <= 'Z')) {
val = (char) (val - LC_OFFSET);
}
header.name[readCount] = val;
readCount++;
pos++;
}
header.nameEnd = readCount - 1;
// Reading the header value (which can be spanned over multiple lines)
maxRead = header.value.length;
readCount = 0;
boolean eol = false;
boolean validLine = true;
while (validLine) {
boolean space = true;
// Skipping spaces
// Note : Only leading white spaces are removed. Trailing white
// spaces are not.
while (space) {
// We're at the end of the internal buffer
if (pos >= count) {
// Copying part (or all) of the internal buffer to the line
// buffer
int val = read();
if (val == -1)
throw new IOException
("requestStream.readline.error");
pos = 0;
}
if ((buf[pos] == SP) || (buf[pos] == HT)) {
pos++;
} else {
space = false;
}
}
while (!eol) {
// if the buffer is full, extend it
if (readCount >= maxRead) {
if ((2 * maxRead) <= HttpHeader.MAX_VALUE_SIZE) {
char[] newBuffer = new char[2 * maxRead];
System.arraycopy(header.value, 0, newBuffer, 0,
maxRead);
header.value = newBuffer;
maxRead = header.value.length;
} else {
throw new IOException
("requestStream.readline.toolong");
}
}
// We're at the end of the internal buffer
if (pos >= count) {
// Copying part (or all) of the internal buffer to the line
// buffer
int val = read();
if (val == -1)
throw new IOException
("requestStream.readline.error");
pos = 0;
}
if (buf[pos] == CR) {
} else if (buf[pos] == LF) {
eol = true;
} else {
// FIXME : Check if binary conversion is working fine
int ch = buf[pos] & 0xff;
header.value[readCount] = (char) ch;
readCount++;
}
pos++;
}
int nextChr = read();
if ((nextChr != SP) && (nextChr != HT)) {
pos--;
validLine = false;
} else {
eol = false;
// if the buffer is full, extend it
if (readCount >= maxRead) {
if ((2 * maxRead) <= HttpHeader.MAX_VALUE_SIZE) {
char[] newBuffer = new char[2 * maxRead];
System.arraycopy(header.value, 0, newBuffer, 0,
maxRead);
header.value = newBuffer;
maxRead = header.value.length;
} else {
throw new IOException
("requestStream.readline.toolong");
}
}
header.value[readCount] = ' ';
readCount++;
}
}
header.valueEnd = readCount;
}
/**
* Read byte.
*/
public int read()
throws IOException {
if (pos >= count) {
fill();
if (pos >= count)
return -1;
}
return buf[pos++] & 0xff;
}
/**
*
*/
/*
public int read(byte b[], int off, int len)
throws IOException {
}
*/
/**
*
*/
/*
public long skip(long n)
throws IOException {
}
*/
/**
* Returns the number of bytes that can be read from this input
* stream without blocking.
*/
public int available()
throws IOException {
return (count - pos) + is.available();
}
/**
* Close the input stream.
*/
public void close()
throws IOException {
if (is == null)
return;
is.close();
is = null;
buf = null;
}
// ------------------------------------------------------ Protected Methods
/**
* Fill the internal buffer using data from the undelying input stream.
*/
protected void fill()
throws IOException {
pos = 0;
count = 0;
int nRead = is.read(buf, 0, buf.length);
if (nRead > 0) {
count = nRead;
}
}
}
HttpRequest
public class HttpRequest {
private String uri;
private String protocol;
private String method;
private InputStream in = null;
public HttpRequest(InputStream in) {
this.in = in;
}
public String getUri() {
return uri;
}
public String getProtocol() {
return protocol;
}
public String getMethod() {
return method;
}
public void setUri(String uri) {
this.uri = uri;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public void setMethod(String method) {
this.method = method;
}
}
HttpRequestFacade
public class HttpRequestFacade {
private HttpRequest request;
public HttpRequestFacade(HttpRequest request) {
this.request = request;
}
public String getUri() {
return request.getUri();
}
public String getProtocol() {
return request.getProtocol();
}
public String getMethod() {
return request.getMethod();
}
}
HttpResponse
public class HttpResponse {
private OutputStream out = null;
public HttpResponse(OutputStream out) {
this.out = out;
}
public void write(byte[] bytes) throws IOException {
out.write(bytes);
out.flush();
}
}
HttpResponseFacade
public class HttpResponseFacade {
private HttpResponse response;
public HttpResponseFacade(HttpResponse response) {
this.response = response;
}
public void write(byte[] bytes) throws IOException {
response.write(bytes);
}
}
setvlet相关
Servlet
public interface Servlet {
public void init();
public void service(HttpRequestFacade request, HttpResponseFacade response);
public void destroy();
}
ServletProcessor
public class ServletProcessor {
public void process(HttpRequestFacade request, HttpResponseFacade response) {
String uri = request.getUri();
String servletName = uri.substring(uri.lastIndexOf("/")+1);
ClassLoader loader = null;
try {
URL[] urls = new URL[1];
File classPath = new File(".class文件路径");
URL classUri = classPath.toURL();
urls[0] = classUri;
loader = new URLClassLoader(urls);
} catch (Exception e) {
e.printStackTrace();
}
Class myClass = null;
try {
myClass = loader.loadClass("connector."+servletName);
}catch (Exception e) {
e.printStackTrace();
}
Servlet servlet = null;
try {
servlet = (Servlet) myClass.newInstance();
servlet.service(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试
测试servlet类–TestControllerServlet
写好测试类后,可以发请求进行测试 http://localhost:8080/servlet/TestControllerServlet
public class TestControllerServlet implements Servlet{
@Override
public void init() {
}
@Override
public void destroy() {
}
@Override
public void service(HttpRequestFacade request, HttpResponseFacade response) {
String message = "HTTP/1.1 200 ok\r\n\r\nTestControllerServlet hello";
try {
response.write(message.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
}
}