基于java Scoket的TCP协议 简单实现http web服务器,使用自定义线程池去处理每个请求,用浏览器看成客户端,达到javaWeb中相似于访问Servlet的效果。 (对http协议和Servlet要有必定了解)html
客户端 (login.html): java
<?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);
}
}
复制代码
连接:pan.baidu.com/s/1zaJy3wK-… 密码:ovgqweb