package com.hcserver.conn; import java.net.InetSocketAddress; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; import com.hcserver.core.OutputBuffer; import com.hcserver.core.Request; import com.hcserver.core.Response; import com.hcserver.process.Process; ; public class Server { public void start() throws Exception { Selector selector = Selector.open(); ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.configureBlocking(false); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); serverSocketChannel.socket().setReuseAddress(true); serverSocketChannel.socket().bind(new InetSocketAddress(8084)); while (true) { int select = selector.select(); if (select == 0) { continue; } Iterator<SelectionKey> selectedKeys = selector.selectedKeys() .iterator(); while (selectedKeys.hasNext()) { SelectionKey key = selectedKeys.next(); if (key.isAcceptable()) { ServerSocketChannel ssc = (ServerSocketChannel) key .channel(); SocketChannel channel = ssc.accept(); if (channel != null) { channel.configureBlocking(false); channel.register(selector, SelectionKey.OP_READ);// 客户socket通道注册读操作 } } else if (key.isReadable()) { SocketChannel channel = (SocketChannel) key.channel(); channel.configureBlocking(false); //创建reqeust对象 Request request = new Request(channel); request.parseHead(); Response response = new Response(channel, selector); // 处理 Process process = new Process(); process.service(request, response); } else if (key.isWritable()) { SocketChannel channel = (SocketChannel) key.channel(); OutputBuffer outputBuffer = (OutputBuffer) key.attachment(); channel.write(outputBuffer.getBuffer()); channel.shutdownOutput(); channel.close(); } selectedKeys.remove(); } } } }
按照规范我们需要实现HttpServletRequest接口和HttpServletResponse接口,这两个接口在Servlet-api.jar这个包中,可以在tomcat的lib目录下找到,也可以从网上下载。另外我们还需要实现自己的PrintWriter和Writer这两个类处理我们Response响应的数据。
package com.hcserver.core; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.security.Principal; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; import java.util.Locale; import java.util.Map; import javax.servlet.AsyncContext; import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.servlet.http.Part; public class Request implements HttpServletRequest{ private SocketChannel channel; private Head head; private Map<String,String> params = new HashMap<>(); private String context; public Request(SocketChannel channel){ this.channel = channel; } public void parseHead(){ //TODO 解析请求头 try { String receive = receive(this.channel); BufferedReader br = new BufferedReader(new StringReader(receive)); this.head = new Head(br); this.head.parseHead(); br.close(); //解析参数 parseParams(); } catch (Exception e) { e.printStackTrace(); } } private void parseParams(){ String url = this.head.getRequestURL(); this.context = url.substring(1,url.indexOf("?")); String params = url.substring(url.indexOf("?")+1,url.length()); String[] split = params.split("&"); for(String param : split){ String[] split2 = param.split("="); this.params.put(split2[0], split2[1]); } } // 接受数据 private String receive(SocketChannel socketChannel) throws Exception { ByteBuffer buffer = ByteBuffer.allocate(1024); byte[] bytes = null; int size = 0; ByteArrayOutputStream baos = new ByteArrayOutputStream(); while ((size = socketChannel.read(buffer)) > 0) { buffer.flip(); bytes = new byte[size]; buffer.get(bytes); baos.write(bytes); buffer.clear(); } bytes = baos.toByteArray(); return new String(bytes); } @Override public String getParameter(String arg0) { return this.params.get(arg0); } @Override public String getContextPath() { return this.context.substring(0,context.indexOf("/")); } @Override public String getServletPath() { return this.context.substring(context.indexOf("/")+1,context.length()); } @Override public ServletContext getServletContext() { return null; } @Override public AsyncContext getAsyncContext() { // TODO Auto-generated method stub return null; } @Override public Object getAttribute(String arg0) { // TODO Auto-generated method stub return null; } @Override public Enumeration<String> getAttributeNames() { // TODO Auto-generated method stub return null; } @Override public String getCharacterEncoding() { // TODO Auto-generated method stub return null; } @Override public int getContentLength() { // TODO Auto-generated method stub return 0; } @Override public String getContentType() { // TODO Auto-generated method stub return null; } @Override public DispatcherType getDispatcherType() { // TODO Auto-generated method stub return null; } @Override public ServletInputStream getInputStream() throws IOException { // TODO Auto-generated method stub return null; } @Override public String getLocalAddr() { // TODO Auto-generated method stub return null; } @Override public String getLocalName() { // TODO Auto-generated method stub return null; } @Override public int getLocalPort() { // TODO Auto-generated method stub return 0; } @Override public Locale getLocale() { // TODO Auto-generated method stub return null; } @Override public Enumeration<Locale> getLocales() { // TODO Auto-generated method stub return null; } @Override public Map<String, String[]> getParameterMap() { // TODO Auto-generated method stub return null; } @Override public Enumeration<String> getParameterNames() { // TODO Auto-generated method stub return null; } @Override public String[] getParameterValues(String arg0) { // TODO Auto-generated method stub return null; } @Override public String getProtocol() { // TODO Auto-generated method stub return null; } @Override public BufferedReader getReader() throws IOException { // TODO Auto-generated method stub return null; } @Override public String getRealPath(String arg0) { // TODO Auto-generated method stub return null; } @Override public String getRemoteAddr() { // TODO Auto-generated method stub return null; } @Override public String getRemoteHost() { // TODO Auto-generated method stub return null; } @Override public int getRemotePort() { // TODO Auto-generated method stub return 0; } @Override public RequestDispatcher getRequestDispatcher(String arg0) { // TODO Auto-generated method stub return null; } @Override public String getScheme() { // TODO Auto-generated method stub return null; } @Override public String getServerName() { // TODO Auto-generated method stub return null; } @Override public int getServerPort() { // TODO Auto-generated method stub return 0; } @Override public boolean isAsyncStarted() { // TODO Auto-generated method stub return false; } @Override public boolean isAsyncSupported() { // TODO Auto-generated method stub return false; } @Override public boolean isSecure() { // TODO Auto-generated method stub return false; } @Override public void removeAttribute(String arg0) { // TODO Auto-generated method stub } @Override public void setAttribute(String arg0, Object arg1) { // TODO Auto-generated method stub } @Override public void setCharacterEncoding(String arg0) throws UnsupportedEncodingException { // TODO Auto-generated method stub } @Override public AsyncContext startAsync() { // TODO Auto-generated method stub return null; } @Override public AsyncContext startAsync(ServletRequest arg0, ServletResponse arg1) { // TODO Auto-generated method stub return null; } @Override public boolean authenticate(HttpServletResponse arg0) throws IOException, ServletException { // TODO Auto-generated method stub return false; } @Override public String getAuthType() { // TODO Auto-generated method stub return null; } @Override public Cookie[] getCookies() { // TODO Auto-generated method stub return null; } @Override public long getDateHeader(String arg0) { // TODO Auto-generated method stub return 0; } @Override public String getHeader(String arg0) { // TODO Auto-generated method stub return null; } @Override public Enumeration<String> getHeaderNames() { // TODO Auto-generated method stub return null; } @Override public Enumeration<String> getHeaders(String arg0) { // TODO Auto-generated method stub return null; } @Override public int getIntHeader(String arg0) { // TODO Auto-generated method stub return 0; } @Override public String getMethod() { // TODO Auto-generated method stub return null; } @Override public Part getPart(String arg0) throws IOException, IllegalStateException, ServletException { // TODO Auto-generated method stub return null; } @Override public Collection<Part> getParts() throws IOException, IllegalStateException, ServletException { // TODO Auto-generated method stub return null; } @Override public String getPathInfo() { // TODO Auto-generated method stub return null; } @Override public String getPathTranslated() { // TODO Auto-generated method stub return null; } @Override public String getQueryString() { // TODO Auto-generated method stub return null; } @Override public String getRemoteUser() { // TODO Auto-generated method stub return null; } @Override public String getRequestURI() { // TODO Auto-generated method stub return null; } @Override public StringBuffer getRequestURL() { // TODO Auto-generated method stub return null; } @Override public String getRequestedSessionId() { // TODO Auto-generated method stub return null; } @Override public HttpSession getSession() { // TODO Auto-generated method stub return null; } @Override public HttpSession getSession(boolean arg0) { // TODO Auto-generated method stub return null; } @Override public Principal getUserPrincipal() { // TODO Auto-generated method stub return null; } @Override public boolean isRequestedSessionIdFromCookie() { // TODO Auto-generated method stub return false; } @Override public boolean isRequestedSessionIdFromURL() { // TODO Auto-generated method stub return false; } @Override public boolean isRequestedSessionIdFromUrl() { // TODO Auto-generated method stub return false; } @Override public boolean isRequestedSessionIdValid() { // TODO Auto-generated method stub return false; } @Override public boolean isUserInRole(String arg0) { // TODO Auto-generated method stub return false; } @Override public void login(String arg0, String arg1) throws ServletException { // TODO Auto-generated method stub } @Override public void logout() throws ServletException { // TODO Auto-generated method stub } public static void main(String[] args) { String content = "hello/MyServlet"; System.out.println(content.substring(0,content.indexOf("/"))); System.out.println(content.substring(content.indexOf("/")+1,content.length())); } }
package com.hcserver.core; import java.io.IOException; import java.io.PrintWriter; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.Collection; import java.util.Locale; import javax.servlet.ServletOutputStream; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; public class Response implements HttpServletResponse{ private SocketChannel channel; private Selector selector; public Response(SocketChannel channel,Selector selector){ this.channel = channel; this.selector = selector; } @Override public PrintWriter getWriter() throws IOException { MyPrintWriter ww = new MyPrintWriter(new OutputBuffer(channel,selector)); return ww; } @Override public void flushBuffer() throws IOException { // TODO Auto-generated method stub } @Override public int getBufferSize() { // TODO Auto-generated method stub return 0; } @Override public String getCharacterEncoding() { // TODO Auto-generated method stub return null; } @Override public String getContentType() { // TODO Auto-generated method stub return null; } @Override public Locale getLocale() { // TODO Auto-generated method stub return null; } @Override public ServletOutputStream getOutputStream() throws IOException { // TODO Auto-generated method stub return null; } @Override public boolean isCommitted() { // TODO Auto-generated method stub return false; } @Override public void reset() { // TODO Auto-generated method stub } @Override public void resetBuffer() { // TODO Auto-generated method stub } @Override public void setBufferSize(int arg0) { // TODO Auto-generated method stub } @Override public void setCharacterEncoding(String arg0) { // TODO Auto-generated method stub } @Override public void setContentLength(int arg0) { // TODO Auto-generated method stub } @Override public void setContentType(String arg0) { // TODO Auto-generated method stub } @Override public void setLocale(Locale arg0) { // TODO Auto-generated method stub } @Override public void addCookie(Cookie arg0) { // TODO Auto-generated method stub } @Override public void addDateHeader(String arg0, long arg1) { // TODO Auto-generated method stub } @Override public void addHeader(String arg0, String arg1) { // TODO Auto-generated method stub } @Override public void addIntHeader(String arg0, int arg1) { // TODO Auto-generated method stub } @Override public boolean containsHeader(String arg0) { // TODO Auto-generated method stub return false; } @Override public String encodeRedirectURL(String arg0) { // TODO Auto-generated method stub return null; } @Override public String encodeRedirectUrl(String arg0) { // TODO Auto-generated method stub return null; } @Override public String encodeURL(String arg0) { // TODO Auto-generated method stub return null; } @Override public String encodeUrl(String arg0) { // TODO Auto-generated method stub return null; } @Override public String getHeader(String arg0) { // TODO Auto-generated method stub return null; } @Override public Collection<String> getHeaderNames() { // TODO Auto-generated method stub return null; } @Override public Collection<String> getHeaders(String arg0) { // TODO Auto-generated method stub return null; } @Override public int getStatus() { // TODO Auto-generated method stub return 0; } @Override public void sendError(int arg0, String arg1) throws IOException { // TODO Auto-generated method stub } @Override public void sendError(int arg0) throws IOException { // TODO Auto-generated method stub } @Override public void sendRedirect(String arg0) throws IOException { // TODO Auto-generated method stub } @Override public void setDateHeader(String arg0, long arg1) { // TODO Auto-generated method stub } @Override public void setHeader(String arg0, String arg1) { // TODO Auto-generated method stub } @Override public void setIntHeader(String arg0, int arg1) { // TODO Auto-generated method stub } @Override public void setStatus(int arg0, String arg1) { // TODO Auto-generated method stub } @Override public void setStatus(int arg0) { // TODO Auto-generated method stub } }
package com.hcserver.core; import java.io.PrintWriter; import java.io.Writer; public class MyPrintWriter extends PrintWriter{ public MyPrintWriter(Writer write){ super(write); } @Override public void print(String s) { super.print(s); } }
package com.hcserver.core; import java.io.IOException; import java.io.Writer; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; public class OutputBuffer extends Writer{ ByteBuffer buffer = ByteBuffer.allocate(1024); private SocketChannel channel; private Selector selector; public OutputBuffer(SocketChannel channel,Selector selector){ this.channel = channel; this.selector = selector; } @Override public void write(char[] cbuf, int off, int len) throws IOException { String content = new String(cbuf); byte[] bytes = content.getBytes(); buffer.put(bytes); buffer.flip(); this.channel.register(selector, SelectionKey.OP_WRITE, this); } @Override public void flush() throws IOException { } @Override public void close() throws IOException { } public ByteBuffer getBuffer() { return buffer; } public void setBuffer(ByteBuffer buffer) { this.buffer = buffer; } }
package com.hcserver.core; import java.io.BufferedReader; import java.io.IOException; /** * http 头信息 * @author chuer * @date 2014-7-10 下午5:07:04 * @version V1.0 */ public class Head { public static final String ACCEPT = "Accept"; public static final String ACCEPT_LANGUAGE = "Accept-Language"; public static final String USER_AGENT = "User-Agent"; public static final String ACCEPT_ENCODING = "Accept-Encoding"; public static final String HOST = "Host"; public static final String DNT = "DNT"; public static final String CONNECTION = "Connection"; public static final String COOKIE = "Cookie"; private BufferedReader br; private String method; private String requestURL; private String protocol; private String agent; private String host; private int port; private String encoding; private String language; private String accept; private String dnt; private String connection; private String cookie; public Head(BufferedReader br){ this.br = br; } public void parseHead(){ String s = null; try { s = br.readLine();//第一行 String[] firstLine = s.split(" "); if(firstLine.length == 3){ this.method = firstLine[0].trim(); this.requestURL = firstLine[1].trim(); this.protocol = firstLine[2].trim(); } //继续读剩下的头信息 s = br.readLine(); while (s !=null) { String[] split = s.split(":"); switch(split[0].trim()){ case ACCEPT:{ this.accept = split[1].trim(); } case ACCEPT_LANGUAGE :{ this.language = split[1].trim(); break; } case USER_AGENT :{ this.agent = split[1].trim(); break; } case ACCEPT_ENCODING :{ this.encoding = split[1].trim(); break; } case HOST :{ this.host = split[1].trim(); break; } case DNT :{ this.dnt = split[1].trim(); break; } case CONNECTION :{ this.connection = split[1].trim(); break; } case COOKIE :{ this.cookie = split[1].trim(); break; } } s = br.readLine(); } } catch (IOException e) { e.printStackTrace(); } } public String getMethod() { return method; } public void setMethod(String method) { this.method = method; } public String getRequestURL() { return requestURL; } public void setRequestURL(String requestURL) { this.requestURL = requestURL; } public String getProtocol() { return protocol; } public void setProtocol(String protocol) { this.protocol = protocol; } public String getAgent() { return agent; } public void setAgent(String agent) { this.agent = agent; } public String getHost() { return host; } public void setHost(String host) { this.host = host; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } public String getEncoding() { return encoding; } public void setEncoding(String encoding) { this.encoding = encoding; } public String getLanguage() { return language; } public void setLanguage(String language) { this.language = language; } public String getAccept() { return accept; } public void setAccept(String accept) { this.accept = accept; } public String getDnt() { return dnt; } public void setDnt(String dnt) { this.dnt = dnt; } public String getConnection() { return connection; } public void setConnection(String connection) { this.connection = connection; } public String getCookie() { return cookie; } public void setCookie(String cookie) { this.cookie = cookie; } }
package com.hcserver.process; import java.io.IOException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Process { public void service(HttpServletRequest request,HttpServletResponse response){ String context = request.getContextPath(); String servletPath = request.getServletPath(); String aa = request.getParameter("aa"); String bb = request.getParameter("bb"); System.out.println("project name = "+context); System.out.println("sevlet name = "+servletPath); System.out.println("param aa = "+aa); System.out.println("param bb = "+bb); try { //返回页面 response.getWriter().print("hello world..."); } catch (IOException e) { e.printStackTrace(); } } }
package com.hcserver; import com.hcserver.conn.Server; public class ServerStartUp { /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { Server server = new Server(); server.start(); } }
启动服务器,浏览器,输入:http://localhost:8084/hello/MySevlet?aa=1&bb=3回车后浏览器显示 hello world..
后台输出
project name = hello sevlet name = MySevlet param aa = 1 param bb = 3