Java写一个简单的Web服务器Socket实现

                    Java写一个简单的Web服务器Socket实现

 

一、实现思路

1、使用 ServerSocket 监听某一端口,然后等待连接获取 Socket对象。

2、创建一个类 HttpServer 继承 java.lang.Thread 类,重写 run()方法,执行浏览器请求。

3、获得浏览器请求,解析资源文件路径。

4、读取资源文件,响应给浏览器。

 

二、代码实现

1、ServerSocket 监听端口,获取 Socket对象

package com.httpserver.two;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * @description: 使用socket 自己写一个web服务器 ---监听端口,获取socket 对象。
 * @version:v1.0
 * @author:w
 * @date:2018年6月6日上午11:03:36
 *
 */
public class WebServer {
	public void startServer(int port){
		try {
			@SuppressWarnings("resource")
			ServerSocket serverSocket = new ServerSocket(port);
			while(true){
				Socket socket = serverSocket.accept();
				new HttpServer(socket).start();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

 

 

2、HttpServer.java类 --- 具体作用看方法注释。

package com.httpserver.two;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

/**
 * @description: 使用socket 实现 web服务器 --- 具体执行读写操作的。
 * @version:v1.0
 * @author:w
 * @date:2018年6月6日上午11:06:20
 *
 */
public class HttpServer extends Thread {
	/**
	 * web资源根路径
	 */
	public static final String ROOT = "c:/";
	
	/**
	 * 输入流对象,读取浏览器请求
	 */
	private InputStream input;
	
	/**
	 * 输出流对象,响应内容给浏览器
	 */
	private OutputStream out;

	/**
	 * @description:初始化socket对象,获取对应 输入,输出流
	 * @param socket
	 */
	public HttpServer(Socket socket) {
		try {
			input = socket.getInputStream();
			out = socket.getOutputStream();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 多线程方法调用
	 */
	@Override
	public void run() {
		String filePath = read();
		response(filePath);
	}

	/**
	 * @description: 读取资源文件,响应给浏览器。
	 * @param:@param filePath
	 *                   资源文件路径
	 * @return:void
	 * @version:v1.0
	 * @author:w
	 * @date:2018年6月6日 上午11:42:37
	 *
	 */
	private void response(String filePath) {
		File file = new File(ROOT + filePath);
		if (file.exists()) {
			// 1、资源存在,读取资源
			try {
				BufferedReader reader = new BufferedReader(new FileReader(file));
				StringBuffer sb = new StringBuffer();
				String line = null;
				while ((line = reader.readLine()) != null) {
					sb.append(line).append("\r\n");
				}
				StringBuffer result = new StringBuffer();
				result.append("HTTP /1.1 200 ok /r/n");
				result.append("Content-Type:text/html /r/n");
				result.append("Content-Length:" + file.length() + "/r/n");
				result.append("\r\n:" + sb.toString());
				out.write(result.toString().getBytes());
				out.flush();
				out.close();
			} catch (Exception e) {
				e.printStackTrace();
			}

		} else {
			// 2、资源不存在,提示 file not found
			StringBuffer error = new StringBuffer();
			error.append("HTTP /1.1 400 file not found /r/n");
			error.append("Content-Type:text/html \r\n");
			error.append("Content-Length:20 \r\n").append("\r\n");
			error.append("

File Not Found..

"); try { out.write(error.toString().getBytes()); out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * * @description:解析资源文件路径 * @example: GET /index.html HTTP/1.1 * @param:@return * @return:String * @version:v1.0 * @author:w * @date:2018年6月6日 上午11:39:42 * */ private String read() { BufferedReader reader = new BufferedReader(new InputStreamReader(input)); try { // 读取请求头, 如:GET /index.html HTTP/1.1 String readLine = reader.readLine(); String[] split = readLine.split(" "); if (split.length != 3) { return null; } System.out.println(readLine); return split[1]; } catch (IOException e) { e.printStackTrace(); } return null; } }

三、代码测试

1、启动服务器

public static void main(String[] args) {
    new WebServer().startServer(8000);
}

 

2、浏览器地址栏输入: http://localhost:8000/index.html

 

3、效果如下:

 

    

Java写一个简单的Web服务器Socket实现_第1张图片

 

四、总结

1、该示例代码可直接粘贴IDE中运行,无需任何第三方jar包。 简单简洁,便于理解。

2、c盘中,必须有一个 index.html的文件,若存放在其他位置,请修改 HttpServer.ROOT字段,路径位置即可。

3、若出现请求成功,响应页面为空白,请去掉 index.html 页面的 标签试试。--- 至于什么问题导致的,目前还不清楚。 -_-!

4、 index.html 代码参考

            




Insert title here


	

Hello World! this is my webserver!

 

五、遗留问题解决

1、若出现请求成功,响应页面为空白,请去掉 index.html 页面的 标签试试。原因是:换行符"\r\n"写错了,写成了"/r/n" 。

2、Firefox无法解析。原因是:"HTTP /1.1 200 ok" 中,"HTTP"和"/1.1" 直接不能有空格,否则 Firefox无法解析 。正确的是: "HTTP/1.1 200 ok"。

3、关于换行符问题补充: 

a. windows 换行符: "\r\n

b. linux 换行符: "\n

c. mac 换行符:"\r"

           4、可能引发问题: 假设在 linux 中,使用 windows的换行符会有效果吗?会引发上述的问题吗?

5、造成上述问题的发生,主要是 response header 不对导致的,chrome 浏览器可查看 response header 如下图:

Java写一个简单的Web服务器Socket实现_第2张图片

 

六、补上修改后的代码 

package com.httpserver.two.fix;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
/**
 * @description: 使用socket 实现 web服务器 --- 具体执行读写操作的。
* fix: 1、换行符写错误:"/r/n" 调整为正确: "\r\n"。
* 2、"HTTP /1.1 200 ok" 中,"HTTP"和"/1.1" 直接不能有空格,否则 Firefox无法解析。
* @version:v1.1 * @author:w * @date:2018年12月18日 16:50:28 */ public class HttpServerFix extends Thread { /** * web资源根路径 */ public static final String ROOT = "c:/"; /** * 输入流对象,读取浏览器请求 */ private InputStream input; /** * 输出流对象,响应内容给浏览器 */ private OutputStream out; /** * @description:初始化socket对象,获取对应 输入,输出流 * @param socket */ public HttpServerFix(Socket socket) { try { input = socket.getInputStream(); out = socket.getOutputStream(); } catch (IOException e) { e.printStackTrace(); } } /** * 多线程方法调用 */ @Override public void run() { String filePath = read(); response(filePath); } /** * @description: 读取资源文件,响应给浏览器。 * @param:@param filePath * 资源文件路径 * @return:void * @version:v1.0 * @author:w * @date:2018年6月6日 上午11:42:37 * */ private void response(String filePath) { File file = new File(ROOT + filePath); if (file.exists()) { // 1、资源存在,读取资源 try { BufferedReader reader = new BufferedReader(new FileReader(file)); StringBuffer sb = new StringBuffer(); String line = null; while ((line = reader.readLine()) != null) { System.out.println("line:"+ line); sb.append(line).append("\r\n"); } StringBuffer result = new StringBuffer(); /** * 1、 换行符"/r/n"写错了,正确的是: "\r\n" * 2、"HTTP /1.1 ..."之间不能有空格,否则Firfox不能解析 * 3、 关于换行符的补充: * a.windows:"\r\n" * b.linux:"\n" * c.mac:"\r" */ // result.append("HTTP /1.1 200 ok /r/n"); result.append("HTTP/1.1 200 ok \r\n"); result.append("Content-Language:zh-CN \r\n"); // charset=UTF-8 解决中文乱码问题 result.append("Content-Type:text/html;charset=UTF-8 \r\n"); result.append("Content-Length:" + file.length() + "\r\n"); result.append("\r\n" + sb.toString()); out.write(result.toString().getBytes()); out.flush(); out.close(); } catch (Exception e) { e.printStackTrace(); } } else { // 2、资源不存在,提示 file not found StringBuffer error = new StringBuffer(); error.append("HTTP/1.1 400 file not found \r\n"); error.append("Content-Type:text/html \r\n"); error.append("Content-Length:20 \r\n").append("\r\n"); error.append("

File Not Found..

"); try { out.write(error.toString().getBytes()); out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * * @description:解析资源文件路径 * @example: GET /index.html HTTP/1.1 * @param:@return * @return:String * @version:v1.0 * @author:w * @date:2018年6月6日 上午11:39:42 * */ private String read() { BufferedReader reader = new BufferedReader(new InputStreamReader(input)); try { // 读取请求头, 如:GET /index.html HTTP/1.1 String readLine = reader.readLine(); String[] split = readLine.split(" "); if (split.length != 3) { return null; } System.out.println(readLine); return split[1]; } catch (IOException e) { e.printStackTrace(); } return null; } }

 

最后,感谢 Vito_w7 的指点迷津!

 

你可能感兴趣的:(Java)