步骤:

1.服务端使用ServerSocket,监听指定的端口。
2.调用ServerSocket的accept方法接收客户端连接,得到Socket对象。
3.根据Socket对象的getInputStream()方法得到输入流,从而拿到浏览器发送的http请求的基本信息。

1
2
3
4
5
6
7
8
9
10
GET /htmlfiles/test2.jsp HTTP/1.1
Host: localhost:9191
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
DNT: 1
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: Hm_lvt_9bd56a6d0766b887592ee921aa94763f=1500436957; __atuvc=47%7C35; _ga=GA1.1.2016651800.1504071340; Hm_lvt_4e003ba2028a4a83d95714c602ee7df5=1507970222; Hm_lvt_47acec2d282c3986f1b600abdc11c7ab=1520665960,1521097911,1521252255,1521540649

4.解析http请求,提取要访问的资源文件的位置,使用Socket的getOutputStream拿到输出流,将文件的内容写到输出流。
5.资源请求完毕,关闭相关的流和Socket。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class Server {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        try {
            serverSocket = new ServerSocket(9191);
            System.out.println("Server已在端口9191启动!");
            while (true) {
                socket = serverSocket.accept();
                InputStream inputStream = socket.getInputStream();
                Request request = new Request(inputStream);
                OutputStream outputStream = socket.getOutputStream();
                Response response = new Response(outputStream, request);
                response.response();
                outputStream.close();
                inputStream.close();
                socket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Request {
    private String uri;
    public Request(InputStream in) {
        try {
            String content = IOUtils.getRequestContent(in);
            if (null == content || "".equals(content)) {
                System.out.println("Bad request.");
                return;
            }
            System.out.println("客户端请求:\n" + content);
            parseUri(content);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private void parseUri(String content) {
        this.uri = content.substring(content.indexOf("/"),content.indexOf("HTTP/")-1);
    }
    public String getUri() {
        return uri;
    }
    public void setUri(String uri) {
        this.uri = uri;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public class Response {
    private Request request;
    private OutputStream os;
    public Response(OutputStream os, Request request) {
        this.os = os;
        this.request = request;
    }
    public void response() {
        String uri = request.getUri();
        if (null != uri && !"".equals(uri)) {
            if (isResource()) {
                String path = Http_Server.WEB_ROOT + uri.substring(1);
                if (IOUtils.isFileExist(path)) {
                    IOUtils.writeFile(os, path);
                } else {
                    String errorMessage = buildResponse("File Not Found","404","");
                    IOUtils.write(os, errorMessage.getBytes());
                }
            } else {
                String errorMessage = buildResponse("动态请求暂不支持","200","OK");
                IOUtils.write(os, errorMessage.getBytes());
            }
        }
    }
    private String buildResponse(String content, String statusCode, String statusMsg) {
        String html = buildHTML(content);
        int chineseCount = StringUtils.getChineseCharCount(html);
        StringBuffer buffer = new StringBuffer();
        buffer.append("HTTP/1.1 ")
                .append(statusCode).append(" ")
                .append(statusMsg).append("\r\n")
                .append("Content-Type: text/html\r\n")
//                .append("Content-Length: ")
//                .append(html.length()+2*chineseCount) // 1个中文字符占3个字节
                .append("\r\n\r\n")
                .append(html);
        return buffer.toString();
    }
    private String buildHTML(String content) {
        StringBuffer html = new StringBuffer();
        html.append("<html>\n");
        html.append("<head>\n");
        html.append("<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n");
        html.append("</head>\n");
        html.append("<body>\n");
        html.append("<h1>").append(content).append("</h1>\n");
        html.append("</body>\n");
        html.append("</html>");
        return html.toString();
    }
    private boolean isResource() {
        String[] suffixs = {"html", "js", "css", "jpg", "jpeg", "gif", "bmp"};
        for (String suf : suffixs) {
            if (request.getUri().endsWith("." + suf)) {
                return true;
            }
        }
        return false;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
public class IOUtils {
    public static String getRequestContent(InputStream inputStream) throws IOException {
        byte[] data = new byte[2048];
        int len = inputStream.read(data);
        if (len > 0) {
            return new String(data,0,len);
        }
        return null;
    }
    public static boolean isFileExist(String path) {
        File file = new File(path);
        return file.exists();
    }
    public static byte[] getFileContent(String path) {
        try {
            File file = new File(path);
            if (file.exists()) {
                byte[] data = new byte[(int) file.length()];
                FileInputStream fis = new FileInputStream(file);
                fis.read(data);
                return data;
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static void write(OutputStream os,byte[] data) {
        try {
            os.write(data);
            os.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void writeFile(OutputStream os,String path) {
        FileInputStream fis = null;
        try {
            int BUFFER_SIZE = 1024;
            fis = new FileInputStream(path);
            byte[] data = new byte[BUFFER_SIZE];
            int len = fis.read(data,0,BUFFER_SIZE);
            boolean isFirst = true;
            while (len != -1) {
                if (isFirst) {
                    os.write("HTTP/1.0 200 OK\r\n".getBytes());
                    os.write("\r\n".getBytes());;// 根据 HTTP 协议, 空行将结束头信息
                    isFirst = false;
                }
                os.write(data,0,len);
                len = fis.read(data,0,BUFFER_SIZE);
                os.flush();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
1
2
3
public class Http_Server {
    public final static String WEB_ROOT = Http_Server.class.getResource("/").getPath();
}

测试HTML

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>测试页面</title>
    <link href="/htmlfiles/css/test.css" rel="stylesheet">
</head>
<body>
    <h1>这是测试页面。<br></h1>
    <a href="http://localhost:9191/htmlfiles/images/1.jpg">点击打开图片</a>
</body>
</html>

资源文件放在src目录下。如图:

测试

1.动态请求测试

2.不存在的静态文件

3.存在的静态文件

4.图片等二进制文件测试

注意

1.你得通过响应头告诉浏览器请求的状态码和资源类型,否则浏览器会告诉你这是无效的http响应。

1
2
os.write("HTTP/1.0 200 OK\r\n".getBytes());
os.write("\r\n".getBytes());;// 根据 HTTP 协议, 空行将结束头信息

2.如果指定了Content-Length,需要注意中文1个字符占用3个字节,否则会导致浏览器显示不全。

1
2
buffer.append("Content-Length: ")
buffer.append(html.length()+2*chineseCount) // 1个中文字符占3个字节