HTTP服务器简易版

 

 

一.读取网页请求,给网页响应文件,该文件是html类型
建3个类,一个服务器,一个解析请求,一个响应用户

 

 

1.请求信息的类:

 

package web;

import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashMap;
import java.util.Map;

public class HttpRequest {
	/*
	 * 请求行相关信息
	 */
	// 请求方法
	private String method;
	// 请求资源路径
	private String url;
	// 请求使用的协议版本
	private String protocol;
	/*
	 * 消息头相关信息
	 */
	private Map<String,String> headers; 

	public HttpRequest(InputStream in) {
		parseRequestLine(in);
		parseHeaders(in);
	}
	public void parseRequestLine(InputStream in) {
		try {
			String line = readLine(in);
			if(line.length()==0){
				throw new RuntimeException("无效请求");
			}
			String[] data = line.split("\\s");
			method = data[0];
			url = data[1];
			protocol = data[2];
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
	}

	public void parseHeaders(InputStream in) {
		headers = new LinkedHashMap<String, String>();
		while (true) {
			String line = readLine(in);
			if ("".equals(line)) {
				break;
			}
			String[] data = line.split(":");
			headers.put(data[0].trim(), data[1].trim());
		}
		headers.forEach((k, v) -> System.out.println(k + ":" + v));
	}
	public String readLine(InputStream in) {
		try {
			StringBuilder builder = new StringBuilder();
			char c1 = 0, c2 = 0;
			int d=-1;
			while ((d=in.read())!=-1) {
				c2 = (char)d;
				if (c1 == 13 && c2 == 10) {
					break;
				}
				builder.append(c2);
				c1 = c2;
			}
			return builder.toString().trim();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return "";
	}
	public String getUrl() {
		return url;
	}
}

 

 

2.响应信息的类:

 

package web;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

public class HttpResponse {
	//状态代码
	private int statusCode;
	// 响应头
	private Map<String,String> headers;
	//响应实体
	private File entity;
	//输出流
	private OutputStream out;
	public HttpResponse(OutputStream out){
		this.out=out;
		this.headers = new HashMap<String,String>();
	}

	public void flush() {
		// 发送状态行信息
		sendResponseStatusLine();
		// 发送响应头信息
		sendReResponseHeaders();
		// 发送响应正文
		sendReResponseContent();
	}
	public void sendResponseStatusLine(){
		String line = "HTTP/1.1"+" "+statusCode+" "+"OK";
		println(line);
	}
	public void sendReResponseHeaders(){
		headers.forEach((k,v)->println(k+":"+v));
		println("");
	}
	public void sendReResponseContent(){
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(entity);
			int len = -1;
			byte[] data = new byte[1024*10];
			while((len = fis.read(data))!=-1) {
				out.write(data, 0, len);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}catch(IOException e) {
			e.printStackTrace();
		}finally {
			if(fis!=null) {
				try {
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	public void println(String line) {
		try {
			out.write(line.getBytes("ISO8859-1"));
			out.write(13);//CR
			out.write(10);//LF
		}catch(UnsupportedEncodingException e) {
			e.printStackTrace();
		}catch(IOException e) {
			e.printStackTrace();
		}
	}
	public void setContentType(String contentType) {
		this.headers.put("Content-Type", contentType);
	}
	public void setContentLength(long length) {
		this.headers.put("Content-Length", String.valueOf(length));
	}
	public void setStatusCode(int statusCode) {
		this.statusCode = statusCode;
	}
	public void setEntity(File entity) {
		this.entity = entity;
	}
}


3.服务器类:

 

 

 

 

package web;

import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 读取网页发送过来的请求行,消息头信息
 * @author soft01
 *
 */
public class WebServer {
	ServerSocket server;
	Socket socket;
	public WebServer() {
		try {
			System.out.println("初始化客户端...");
			server = new ServerSocket(8088);
			System.out.println("客户端初始化完毕!");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public void start() {
		try {
			while (true) {
				System.out.println("等待客户端连接...");
				socket = server.accept();
				System.out.println("一个客户端已连接!");
				// 1:请求行 method url protocol
				// 2:消息头:根据请求资源的不同消息头中的内容也不完全一样。
				// 消息头中每一个信息都以CRLF结束
				// CR(13)LF(10) 单独读取到一个CRLF表示消息头全部发送完毕
				// 3:消息正文
				ClientHandler handler = new ClientHandler(socket);
				Thread t = new Thread(handler);
				t.start();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public static void main(String[] args) {
		try {
			WebServer server = new WebServer();
			server.start();
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	private class ClientHandler implements Runnable {
		private Socket socket;
		public ClientHandler(Socket socket) {
			this.socket=socket;
		}

		public void run() {
			try {
				HttpRequest request = new HttpRequest(socket.getInputStream());
				HttpResponse response = new HttpResponse(socket.getOutputStream());
				String url = request.getUrl();
				System.out.println(url);
				File file = new File("web-apps" + url);
				if(file.exists()) {
					// 设置状态码
					response.setStatusCode(200);
					// 设置Content-Type
					response.setContentType("text/html");
					response.setContentLength(file.length());
					// 设置实体数据
					response.setEntity(file);
					response.flush();
				}else {
					System.out.println("文件不存在!");
				}
			} catch (Exception e) {
				e.printStackTrace();
			}finally {
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}


二.读取网页请求,给网页响应文件,相关信息用xml配置(需要导入dom4j包)

1.项目根目录下创建文件如下:

(1)conf目录下建server.xml和web.xml文件

server.xml如下:

 

 

 

 

<?xml version="1.0" encoding="UTF-8"?>
<server>
	<!-- 配置和客户端连接相关的信息客户端传输数据的字符集服务端口等信息 -->
	<Connector URIEncoding="utf-8" port="8088" protocol="HTTP/1.1"/>
	<!-- 线程池的线程数 -->
	<Executor maxThreads="50"/>
</server>


web.xml如下:

 

 

 

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1">
	<mime-mapping>
		<extension>html</extension>
		<mime-type>text/html</mime-type>
	</mime-mapping>
	<mime-mapping>
		<extension>jpg</extension>
		<mime-type>image/jpeg</mime-type>
	</mime-mapping>
	<mime-mapping>
		<extension>jpgm</extension>
		<mime-type>video/jpm</mime-type>
	</mime-mapping>
	<mime-mapping>
		<extension>7z</extension>
		<mime-type>application/x-7z-compressed</mime-type>
	</mime-mapping>
</web-app>


(2)web-apps目录下建myweb目录,myweb里面的文件建index.html和reg.html和图片bee0.png

index.html如下:

 

 

 

 

<html>
	<head>
		<title>hello</title>
		<meta charset="UTF-8">
	</head>
	<body>
		<center>
		<h1>这是我的第一个页面</h1>
		<img src="bee0.png">
		<a href="reg.html">去注册</a>
		</center>
	</body>
</html>


reg.html如下:

 

 

 

 

<html>
	<head>
		<title>欢迎注册</title>
		<meta charset="UTF-8">
	</head>
	<body>
		<center>
		<h1>用户注册</h1>
		<table border="1">
			<tr>
				<td>用户名:</td>
				<td><input name ="username" type="text" size=30></td>
			</tr>
			<tr>
				<td>密 码:</td>
				<td><input name ="password" type="password" size=30></td>
			</tr>
			<tr>
				<td colspan="2" align="center">
					<input type="submit" value="注册">
				</td>
			</tr>
		</table>
		</center>
	</body>
</html>


2.建5个类,一个服务器,一个请求解析,一个响应用户,一个服务器配置信息,一个Http协议相关定义信息

(1)服务器配置信息解析server.xml

 

 

 

package web.v2;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
* 服务端配置数据
* 通过解析conf/server.xml文件得到配置数据
* @author soft01
*
*/
public class Server {
	public static String URIENCODEING;
	public static int PORT;
	public static String PROTOCOL;
	public static int MAX_THREADS;
	static {
		try {
			SAXReader reader = new SAXReader();
			Document doc = reader.read(new FileInputStream("conf"+File.separator+"server.xml"));
			Element root = doc.getRootElement();
			Element ele1 = root.element("Connector");
			URIENCODEING = ele1.attributeValue("URIEncoding");
			PORT = Integer.parseInt(ele1.attributeValue("port"));
			PROTOCOL =ele1.attributeValue("protocol");
			Element ele2 = root.element("Executor");
			MAX_THREADS = Integer.parseInt(ele2.attributeValue("maxThreads"));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (DocumentException e) {
			e.printStackTrace();
		}
	}
}


(2)Http协议相关定义信息解析web.xml

 

package web.v2;

import java.io.File;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * Http协议相关定义信息
 * @author soft01
 *
 */
public class HttpContext {
	public static final int CR = 13;
	public static final int LF = 10;
	public static final int STATUS_CODE_OK = 200;
	public static final int STATUS_CODE_NOT_FOUND = 404;
	public static final int STATUS_CODE_ERROR = 500;
	public static final Map<Integer,String> STATUS_CODE_MAPPING = new HashMap<Integer,String>();
	public static final Map<String,String> MIME_MAPPING = new HashMap<String,String>();
	static {
		initCodeMapping();
		initMimeMapping();
	}
	private static void initCodeMapping() {
		STATUS_CODE_MAPPING.put(200, "ok");
		STATUS_CODE_MAPPING.put(404, "not found");
		STATUS_CODE_MAPPING.put(500, "internal server error");
	}
	private static void initMimeMapping() {
		/*
		 * 解析当前目录下的子目录conf中的文件web.xml
		 * 将该文件中所有<mime-mapping>标签中内容
		 * 存入MIME_MAPPING这个Map中
		 * 其中Key为<extension>标签中的文本信息
		 * value为<mime-type>标签中的文本信息
		 */
		try {
			SAXReader reader = new SAXReader();
			Document doc = reader.read(new FileInputStream("conf"+File.separator+"web.xml"));
			Element root = doc.getRootElement();
			List<Element> eles = root.elements("mime-mapping");
			for(Element ele : eles) {
				MIME_MAPPING.put(ele.elementText("extension"), ele.elementText("mime-type"));
			}
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
}


(3)请求解析

 

 

 

package web.v2;

import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashMap;
import java.util.Map;

public class HttpRequest {
	/*
	 * 请求行相关信息
	 */
	// 请求方法
	private String method;
	// 请求资源路径
	private String url;
	// 请求使用的协议版本
	private String protocol;
	/*
	 * 消息头相关信息
	 */
	private Map<String,String> headers; 

	public HttpRequest(InputStream in) {
		parseRequestLine(in);
		parseHeaders(in);
	}
	public void parseRequestLine(InputStream in) {
		try {
			String line = readLine(in);
			if(line.length()==0){
				throw new RuntimeException("无效请求");
			}
			String[] data = line.split("\\s");
			method = data[0];
			url = data[1];
			protocol = data[2];
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
	}
	public void parseHeaders(InputStream in) {
		headers = new LinkedHashMap<String, String>();
		while (true) {
			String line = readLine(in);
			if ("".equals(line)) {
				break;
			}
			String[] data = line.split(":");
			headers.put(data[0].trim(), data[1].trim());
		}
		headers.forEach((k, v) -> System.out.println(k + ":" + v));
	}
	public String readLine(InputStream in) {
		try {
			StringBuilder builder = new StringBuilder();
			char c1 = 0, c2 = 0;
			int d=-1;
			while ((d=in.read())!=-1) {
				c2 = (char)d;
				if (c1 == HttpContext.CR && c2 == HttpContext.LF) {
					break;
				}
				builder.append(c2);
				c1 = c2;
			}
			return builder.toString().trim();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return "";
	}
	public String getUrl() {
		return url;
	}
}


(4)响应用户

 

 

 

 

package web.v2;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

public class HttpResponse {
	//状态代码
	private int statusCode;
	// 响应头
	private Map<String,String> headers;
	//响应实体
	private File entity;
	//输出流
	private OutputStream out;
	public HttpResponse(OutputStream out){
		this.out=out;
		this.headers = new HashMap<String,String>();
	}

	public void flush() {
		// 发送状态行信息
		sendResponseStatusLine();
		// 发送响应头信息
		sendReResponseHeaders();
		// 发送响应正文
		sendReResponseContent();
	}
	public void sendResponseStatusLine(){
		String line = Server.PROTOCOL+" "+statusCode+" "+HttpContext.STATUS_CODE_MAPPING.get(statusCode);
		println(line);
	}
	public void sendReResponseHeaders(){
		headers.forEach((k,v)->println(k+":"+v));
		println("");
	}
	public void sendReResponseContent(){
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(entity);
			int len = -1;
			byte[] data = new byte[1024*10];
			while((len = fis.read(data))!=-1) {
				out.write(data, 0, len);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}catch(IOException e) {
			e.printStackTrace();
		}finally {
			if(fis!=null) {
				try {
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	public void println(String line) {
		try {
			out.write(line.getBytes("ISO8859-1"));
			out.write(HttpContext.CR);//CR
			out.write(HttpContext.LF);//LF
		}catch(UnsupportedEncodingException e) {
			e.printStackTrace();
		}catch(IOException e) {
			e.printStackTrace();
		}
	}
	public void setContentType(String contentType) {
		this.headers.put("Content-Type", contentType);
	}
	
	public void setContentLength(long length) {
		this.headers.put("Content-Length", String.valueOf(length));
	}
	public void setStatusCode(int statusCode) {
		this.statusCode = statusCode;
	}
	public void setEntity(File entity) {
		this.entity = entity;
	}
}


(5)服务器

 

 

 

 

 

 

package web.v2;

import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 读取网页发送过来的请求行,消息头信息
 * @author soft01
 *
 */
public class WebServer {
	ServerSocket server;
	Socket socket;
	private ExecutorService threadPool;
	public WebServer() {
		try {
			System.out.println("初始化客户端...");
			server = new ServerSocket(Server.PORT);
			threadPool = Executors.newFixedThreadPool(Server.MAX_THREADS);
			System.out.println("客户端初始化完毕!");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public void start() {
		try {
			while (true) {
				System.out.println("等待客户端连接...");
				socket = server.accept();
				System.out.println("一个客户端已连接!");
				// 1:请求行 method url protocol
				// 2:消息头:根据请求资源的不同消息头中的内容也不完全一样。
				// 消息头中每一个信息都以CRLF结束
				// CR(13)LF(10) 单独读取到一个CRLF表示消息头全部发送完毕
				// 3:消息正文
				ClientHandler handler = new ClientHandler(socket);
				threadPool.execute(handler);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public static void main(String[] args) {
		try {
			WebServer server = new WebServer();
			server.start();
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	private class ClientHandler implements Runnable {
		private Socket socket;
		public ClientHandler(Socket socket) {
			this.socket=socket;
		}

		public void run() {
			try {
				HttpRequest request = new HttpRequest(socket.getInputStream());
				HttpResponse response = new HttpResponse(socket.getOutputStream());
				String url = request.getUrl();
				File file = new File("web-apps" + url);
				if(file.exists()) {
					// 设置状态码
					response.setStatusCode(HttpContext.STATUS_CODE_OK);
					// 设置Content-Type
					String fileName = file.getName();
					int index = fileName.lastIndexOf(".")+1;
					String extension = fileName.substring(index);
					String contentType = HttpContext.MIME_MAPPING.get(extension);
					response.setContentType(contentType);
					response.setContentLength(file.length());
					// 设置实体数据
					response.setEntity(file);
					response.flush();
				}else {
					System.out.println("文件不存在!");
				}
			} catch (Exception e) {
				e.printStackTrace();
			}finally {
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

linsa_pursuer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值