基于java Scoket的TCP协议 简单实现http web服务器,使用自定义线程池去处理每一个请求,用浏览器当作客户端,达到javaWeb中类似于访问Servlet的效果。 (对http协议和Servlet要有一定了解)
测试账号:zjl 123456
<?xml version="1.0" encoding="UTF-8" ?> <web-app> <servlet> <servlet-name>LoginServlet</servlet-name> <servlet-class>demo.ServletImpl.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>LoginServlet</servlet-name> <url-pattern>/login</url-pattern> </servlet-mapping> </web-app> 复制代码
public class startServer { private static RequestThreadPool<ServerThread> requestThreadPool = new RequestThreadPool<>(); public static void main(String[] args) throws Exception { ServerSocket server = new ServerSocket(8080); System.out.println("http服务器启动成功...."); //多线程处理每个请求 while(true){ Socket client = server.accept(); //阻塞式等待接收一个请求 // new ServerThread(client).start(); 旧版 requestThreadPool.execute(new ServerThread(client)); } } /** * 服务器处理浏览器请求线程 */ static class ServerThread extends Thread{ private Request request; //请求 private Response reponse; //响应 private Socket client; //初始化request,reponse public ServerThread(Socket client) { try { this.client = client; request = new Request(client.getInputStream()); reponse = new Response(client.getOutputStream()); } catch (Exception e) { e.printStackTrace(); } } @Override public void run() { try { System.out.println(client.getRemoteSocketAddress()+" 发出请求"); //浏览器会默认请求网站图标资源,我们这里忽略掉这个请求 if (request.getUrl().equals("/favicon.ico")) return; //1-根据请求的url获得Servlet Servlet servlet = ServletFactory.getServlet(request.getUrl()); //请求资源不存在404 if (servlet == null){ reponse.setCode(404); reponse.print(""); } //2-执行Servlet if (servlet != null){ servlet.service(request,reponse); } } catch (Exception e) { e.printStackTrace(); }finally { try { client.close(); } catch (IOException e) { e.printStackTrace(); } } } } } 复制代码
package demo3.util; import java.util.*; import java.util.concurrent.atomic.AtomicLong; /** * 自定义处理请求的线程池 * * * */ public class RequestThreadPool<Job extends Runnable> { //任务列表 (线程池) private final LinkedList<Job> jobsList = new LinkedList<>(); //工作线程队列 private final List<MyWorker> workerList = Collections.synchronizedList(new ArrayList<MyWorker>()); //默认工作者线程数量 private static final int DEFAULT_WORKER_NUMBERS = 5; //工作者编号生成序号 private AtomicLong threadNum = new AtomicLong(); // 构造方法 public RequestThreadPool(){ initWorkerThreadByNum(DEFAULT_WORKER_NUMBERS); } public RequestThreadPool(int workerNum){ initWorkerThreadByNum(workerNum); } public void initWorkerThreadByNum(int workerNum){ for (int i = 0; i < workerNum; i++) { MyWorker worker = new MyWorker(); workerList.add(worker); //工作线程开始消费任务 new Thread (worker, "ThreadPool-Worker-"+ threadNum.incrementAndGet()).start(); } } //把任务交给线程池,之后工作线程回去消费它 public void execute(Job job) { if (job != null){ synchronized (jobsList){ jobsList.addLast(job); System.out.println("剩余待处理请求个数:"+RequestThreadPool.this.getJobsize()); jobsList.notify(); //随机唤醒在此jobsList锁上等待的工作者线程 } } } //通知所有的工作者线程 public void shutdown() { for (MyWorker e : workerList) { e.shutdown(); } } //获取剩余任务个数 public int getJobsize() { return jobsList.size(); } /** * 工作线程,消费任务 */ private class MyWorker implements Runnable{ //是否工作 private volatile boolean isRunning = true; @Override public void run() { while(isRunning){ Job job = null; //同步获取任务 synchronized(jobsList){ //如果任务列表为空就等待 while(jobsList.isEmpty()){ try { jobsList.wait(); } catch (InterruptedException e) { //感知到被中断就退出 return; } } //获取任务 job = jobsList.removeFirst(); } //执行任务 if (job != null){ System.out.println("正在处理请求"); job.run(); System.out.println("处理完成,剩余待处理请求个数:"+RequestThreadPool.this.getJobsize()); } } } //关闭线程 public void shutdown(){ isRunning = false; } } } 复制代码
/** * Servlet工厂 * * 根据url和xml文件创建Servlet * * */ public class ServletFactory { //Servlet上下文环境 private static ServletContext context = new ServletContext(); //web.xml文件路径 private static String xmlpath = "http服务器/src/demo/web.xml"; private ServletFactory(){} /** * 读取web.xml文件把servlet和url的关系进行配置存储 */ static { try { //1-获得doucument SAXReader saxReader = new SAXReader(); Document document = saxReader.read(new File(xmlpath)); //2-获得根元素 <web-app> Element rootElement = document.getRootElement(); //3-获得所有子元素 List<Element> elements = rootElement.elements(); //4-遍历处理所有子元素 for (Element e : elements) { if ("servlet-mapping".equals(e.getName())) { Element servlet_name = e.element("servlet-name"); Element url_pattern = e.element("url-pattern"); context.getUrl_map().put(url_pattern.getText(),servlet_name.getText()); } else if ("servlet".equals(e.getName())) { Element servlet_name = e.element("servlet-name"); Element servlet_class = e.element("servlet-class"); context.getServlet_map().put(servlet_name.getText(),servlet_class.getText()); } } } catch (DocumentException e) { e.printStackTrace(); } } /** * 获得Servlet */ public static synchronized Servlet getServlet(String url) throws Exception { String servletClass = context.getServlet_map().get(context.getUrl_map().get(url)); if (servletClass != null) return (Servlet)Class.forName(servletClass).newInstance(); else return null; } } 复制代码
/** * Servlet的上下文环境 */ public class ServletContext { //Servlet别名和Servlet全路径类名的映射关系 private Map<String,String> servlet_map; //url和 Servlet别名的映射关系 private Map<String,String> url_map; public ServletContext() { servlet_map = new HashMap<>(); url_map = new HashMap<>(); } public Map<String, String> getServlet_map() { return servlet_map; } public Map<String, String> getUrl_map() { return url_map; } } 复制代码
/** * Servlet抽象类 */ public abstract class Servlet { public void service(Request request,Response reponse) throws Exception { this.doGet(request,reponse); this.doPost(request,reponse); } public abstract void doGet(Request request,Response reponse) throws Exception; public abstract void doPost(Request request,Response reponse) throws Exception; } 复制代码
import demo.domain.Request; import demo.domain.Response; import demo.domain.Servlet; public class LoginServlet extends Servlet { @Override public void doGet(Request request, Response reponse) throws Exception { String name = request.getParameter("name"); String password = request.getParameter("password"); if (name!= null && password !=null && name.equals("zjl") && password.equals("123456")) reponse.print("登陆成功!"); else reponse.print("登陆失败!"); } @Override public void doPost(Request request, Response reponse) throws Exception { doGet(request,reponse); } } 复制代码