Java使用Scoket实现一个简单的Web服务器

一、项目介绍

该项目是用JAVA使用Scoket实现一个简单的Web服务器,项目的实现受到了 HaHa_Sir《Java写一个简单的Web服务器Socket实现》 的启发。

项目已实现功能:

  1. 用户能自由设置WebServer端口(1024-65535);
  2. 允许多个用户同时访问服务器;
  3. 实现HTML和JPG图片的解析;
  4. 资源文件实现相对路径解析;

二、整体思路

实现WebServer的逻辑是很清晰的:

  1. 设置WebServer端口号,其范围在1024-65535之间;
  2. 使用 **ServerSocket.accept()**方法,轮询监听用户请求;
  3. 用户使用浏览器输入地址,向WebServer发出请求;
  4. 服务器监听到用户请求,为该请求新建一个HttpServer来处理该请求;
  5. HttpServer解析用户请求并作出响应;
  6. 用户浏览器显示响应结果;

三、代码实现

该项目为WebServer,整个项目包含两个java文件,分别是webserver.java 和 httpserver.java。

1. WebServer.java

其中,WebServer.java 是整个项目的主线程,用于设置服务器端口号;监听用户的请求,为每一个监听到的请求新建一个httpserver线程,来处理用户请求。

函数介绍
public static void startServer(int port)轮询serverSocket.accept(),监听用户请求,为每一个监听到的请求,新建一个httpserver线程响应
public static void main(String[] args)用于根据用户输入来设置服务器端口号,其后,启动Webserver服务器
package com.webServer;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;


public class WebServer {
	
	public static 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();
		}

	}
	
	
	public static void main(String[] args){
		@SuppressWarnings("resource")
		Scanner in =new Scanner(System.in);
		System.out.print("Please input the Port Number( 1024 -65535 ):");
		int portNumber=80;
		do{
			portNumber=in.nextInt();
			if(portNumber>=1024 && portNumber <= 65535 )
				break;
			else
				System.out.print("The Input Port Number is wrong,please input again( 1024 -65535 ):");
		}while(in.hasNext());
		System.out.println("**********WebServer start!*********");
		startServer(portNumber);
	}
}

2. Httpserver.java

Httpserver.java 继承自Thread,用于读取用户访问路径,根据路径响应请求。

函数介绍
public HttpServer(Socket socket)初始化socket对象,获取对应 输入,输出流
public void run()重载Run()函数,调用Read()、response()函数
private void response(String filePath)根据读取的路径,进行响应。以流的形式读取文件,再以流的形式输出文件
private String read()解析请求路径
package com.webServer;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
 

public class HttpServer extends Thread {
	//web资源路径,此处为相对路径
	public static final String ROOT = "./resource";
	
	//输入流对象,读取浏览器请求
	private InputStream input;
	
	//输出流对象,响应内容给浏览器
	private OutputStream out;
	
	//因为编码问题,text/html,若直接使用out输出会使用默认编码,而不是UTF-8,因此会导致中文乱码
	private OutputStreamWriter osw;
 
    //初始化socket对象,获取对应 输入,输出流
	public HttpServer(Socket socket) {
		try {
			input = socket.getInputStream();
			out = socket.getOutputStream();
			osw = new OutputStreamWriter(socket.getOutputStream(), "UTF-8");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
 
	//多线程方法调用
	@Override
	public void run() {
		String filePath = read();
		response(filePath);
	}
 
	private void response(String filePath) {
		File file = new File(ROOT + filePath);
    	//System.out.println("filePath:"+filePath);
  	    System.out.println("filePath():"+file.getPath());
     	//System.out.println("file.getName():"+file.getName());
  		
		//防止用户直接输入"localhost:portnumber",导致路径为".\resource"而出现错误。
		if (file.exists() && !file.getPath().equals(".\\resource")) {
			//资源存在,读取资源
			try {
				//获取文件类型,判断Content-Type
				String fileType =file.getName().split("\\.")[1];
				//System.out.println("fileType:"+fileType);
				if(fileType.equals("html")) {
					FileInputStream fis = new FileInputStream(file);   
					InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
					BufferedReader reader = new BufferedReader(isr);
					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("accept-ranges: bytes \r\n");
					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());
					//System.out.println(result.toString());   
					osw.write(result.toString());   
					osw.flush();
					osw.close();
					fis.close();
					isr.close();
					reader.close();
				}else if(fileType.equals("jpg")) {
					StringBuffer result = new StringBuffer();
					result.append("HTTP/1.1 200 OK \r\n");
					result.append("accept-ranges: bytes \r\n");
					result.append("Content-Type:image/jpeg \r\n");
					result.append("Content-Length:" + file.length() + "\r\n");
					result.append("\r\n");
					//System.out.println(result.toString());   
					out.write(result.toString().getBytes());   
					FileInputStream fis = new FileInputStream(file);
						byte[] buf=new byte[1024];
						int len=0; 
				    while((len=fis.read(buf))!=-1){
				       out.write(buf,0,len);
				    }
					out.flush();
					out.close();
					fis.close();
				}
				
			} catch (Exception e) {
				e.printStackTrace();                                    
			}
 
		} else {   
			//资源不存在,提示 File not found
			try {
				StringBuffer error = new StringBuffer();
				String html="<h1>404 File Not Found.</h1>";
				
				error.append("HTTP/1.1 404 Not Found \r\n");
				error.append("Content-Type:text/html;charset=UTF-8 \r\n");
				error.append("Content-Length:").append(html.length()).append("\r\n").append("\r\n");
				error.append(html);

				osw.write(error.toString());
				osw.flush();
				osw.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
 
	}
 
    //解析请求路径
	private String read() {
		BufferedReader reader = new BufferedReader(new InputStreamReader(input));
		try {
			// 读取请求头, 如:GET /index.html HTTP/1.1
			String readLine = reader.readLine();
			// 防止用户直接输入"localhost:portnumber"而出现错误。
			System.out.println(readLine);
			if(readLine==null)
				return "/";
			String[] split = readLine.split(" ");
			if (split.length != 3) {
				return "/";
			}
			return split[1];
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

}

3.Index.html

用户请求的页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebServerIndex</title>
</head>
<body>
<div style="margin-top: 5%; text-align: center;height: 100%;">
<!-- 该图片路径为resource下的相对路径,若想放自己的图片,则将其命名为picture.jpg即可 -->
    <img src="/picture.jpg" alt=""/>
    <h1 style="font-size: 72px">Hello World!你好,世界!</h1>
</div>
</body>
</html>

4.资源路径

为了项目的可移植性,文件的解析路径是相对路径,整个文件都放在文件夹resource下(若想修改相对路径,在HttpServer.java ROOT中修改即可)。
resource
resource文件夹下文件示例:
resource文件夹下文件示例

四、项目测试

  1. 将项目导出jar包;
  2. 在windows 系统cmd下,输入java -jar WebServer.jar运行WebServer.jar,根据提示,输入合适的端口号,运行webServer;
    在这里插入图片描述
  3. 用户使用浏览器进行请求(这里使用的请求链接是 http://localhost:1025/index.html 1025 为我们输入设置的端口号);
    在这里插入图片描述
  4. 与此同时,cmd运行的WebServer情况如下;
    在这里插入图片描述
    备注:Index.html在WebServer.jar路径下resource文件夹下
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值