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="

404 File Not Found.

"; 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

用户请求的页面




    
    WebServerIndex


Hello World!你好,世界!

4.资源路径

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


1.jpg

resource文件夹下文件示例:


2.jpg

四、项目测试

  1. 将项目导出jar包;

  2. 在windows 系统cmd下,输入java -jar WebServer.jar运行WebServer.jar,根据提示,输入合适的端口号,运行webServer;


    5.jpg
  3. 用户使用浏览器进行请求(这里使用的请求链接是 http://localhost:1025/index.html 1025 为我们输入设置的端口号);

    4.jpg

  4. 与此同时,cmd运行的WebServer情况如下;


    3.jpg

备注:Index.html在WebServer.jar路径下resource文件夹下

作者简介:一木一生,一个散发着单身狗清香的程序猿。同时,欢迎关注我的CSDN博客 Vito_w7

本文为作者原创,未经允许,不得转载,违者必究!

你可能感兴趣的:(Java使用Scoket实现一个简单的Web服务器)