引言
本文利用 java 自带的 socket 编程实现了一个简单的静态资源服务器, 可以响应静态资源. 本文一共有两个版本的源码. 第一个版本名为 Server_v1, 该版本实现了一个简单的 socket 的服务器, 帮助读者回忆 socket 编程. 第二个版本名为 Server_v2, 该版本是对第一版的改良, 给出了改良思路, 做出了必要的封装, 让其能够响应 CSS,html,jpg 等静态资源.
版本一
该版本实现一个简单的 socket 服务器, 针对浏览器的请求, 能够返回相应的页面.
其源码如下:
- package mytomcat_v1;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.net.ServerSocket;
- import java.net.Socket;
- import java.util.Date;
- /**
- *
- * @author zhengrongjun
- * @version v1.0
- */
- public class Server_V1 {public static void main(String[] args) {
- ServerSocket serverSocket = null;
- Socket client = null;
- try {
- serverSocket = new ServerSocket(9999);
- // 不断接收客户连接
- while (true) {
- // 服务器阻塞等待客户端 socket 连接过来
- client = serverSocket.accept();
- // 对客户端里面端请求信息进行处理
- InputStream in = client.getInputStream();
- // 定义一个读取缓冲池 主要是在 inputstram 流中读取字节
- byte[] buff = new byte[1024];
- int len = in.read(buff);
- if (len> 0) {
- String msg = new String(buff, 0, len);
- System.out.println("===="+msg+"======");
- OutputStream out = client.getOutputStream();
- // 构建响应信息
- StringBuffer sb = new StringBuffer();
- sb.append("HTTP/1.1 200 OK\n");
- sb.append("Content-Type: text/html; charset=UTF-8\n");
- sb.append("\n");
- String html="<html><head><title > 卖烧饼咯 </title></head></html><body > 小曲经常在"
- +"<font size='14'color='red'>"
- +new Date()
- +"</font>"
- +"<br/> 卖烧饼 </body></html>";
- sb.append(html);
- out.write(sb.toString().getBytes());
- out.flush();
- out.close();
- }
- }
- } catch (Exception e) {
- }
- }
- }
执行效果如下图所示, 打开 chrome 浏览器, 在导航栏输入
http://localhost:9999/docs/index.html
显示如下图所示
控制台输出如下图所示
- ====GET /docs/index.html HTTP/1.1
- Host: localhost:9999
- Connection: keep-alive
- Upgrade-Insecure-Requests: 1
- User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) ApplewebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
- Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
- Accept-Encoding: gzip, deflate, br
- Accept-Language: zh-CN,zh;q=0.9
- ======
版本二
该版本在版本一的基础上进行优化, 使其能够有效的响应静态资源
步骤一
先看第一部分代码优化, 如下图所示
红框的部分, 我们可以理解为对请求信息对处理, 因此我们模仿 Tomcat 构造一个 HttpRequst 来处理这一段逻辑.
另外, 我们需要对静态资源进行响应, 因此我们需要获取输入内容的静态资源地址, 即以下部分的内容.
获取以上红框请求地址内容的代码如下
uri = msg.substring(msg.indexOf("/"),msg.indexOf("HTTP/1.1") - 1);
综上所述, 我们有 HttpRequest 类如下所示
- package mytomcat_v2;
- import java.io.IOException;
- import java.io.InputStream;
- /**
- * 对客户端进行处理对业务类
- *
- * @author zhengrongjun
- *
- */
- public class HttpRequest {
- private String uri;
- public String getUri() {
- return uri;
- }
- public HttpRequest(InputStream in) throws IOException {
- // 对我们对请求字节流进行解析
- resolverRequest(in);
- }
- private void resolverRequest(InputStream in) throws IOException {
- // TODO Auto-generated method stub
- byte[] buff = new byte[1024];
- int len = in.read(buff);
- if (len> 0) {
- String msg = new String(buff, 0, len);
- System.out.println("====" + msg + "======");
- // 解析出来 uri
- uri = msg.substring(msg.indexOf("/"), msg.indexOf("HTTP/1.1") - 1);
- } else {
- System.out.println("bad Request!");
- }
- }
- }
步骤二
接下来是第二部分的代码优化, 如下图所示
以上红框部分主要是对输出信息进行响应, 我们模仿 tomcat 构造一个 HttpResponse 对象封装该部分逻辑.
另外, 我们获取用户请求的资源文件路径, 根据该路径找到相应静态文件. 将该文件写入文件流, 输出.
因此, 我们有 HttpResponse 对象如下所示
- package mytomcat_v2;
- /**
- * 封装 http 响应信息
- * @author zhengrongjun
- *
- */
- import java.io.FileInputStream;
- import java.io.IOException;
- import java.io.OutputStream;
- public class HttpResponse {
- private OutputStream os = null;
- public HttpResponse(OutputStream os) {
- this.os = os;
- }
- public void writerFile(String path) throws IOException {
- FileInputStream fileInputStream = new FileInputStream(path);
- byte[] buff = new byte[1024];
- int len = 0;
- // 构建响应信息
- StringBuffer sb = new StringBuffer();
- sb.append("HTTP/1.1 200 OK\n");
- sb.append("Content-Type: text/html; charset=UTF-8\n");
- sb.append("\n");
- os.write(sb.toString().getBytes());
- while ((len = fileInputStream.read(buff)) != -1) {
- os.write(buff, 0, len);
- }
- fileInputStream.close();
- os.flush();
- os.close();
- }
- }
步骤三
接下来我们构建测试类, 构建之前我们先去找一些静态资源文件. 作者直接去 apache 的官网下把 tomcat 给下了下来, 然后去如下目录拷贝静态资源文件
apache-tomcat-8.5.28/webapps/docs
将整个 docs 文件夹拷贝至你的项目的根目录下
apache-tomcat-8.5.28/webapps/ROOT/favicon.ico
将 favicon.ico 图片拷贝至你的根目录下
静态资源在你的项目中的结构如下图所示
现在上我们的 Server_V2 的代码
- package mytomcat_v2;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.net.ServerSocket;
- import java.net.Socket;
- import java.util.Date;
- /**
- *
- * @author zhengrongjun
- * @version v2.0
- */
- public class Server_V2 {
- public static void main(String[] args) {
- ServerSocket serverSocket = null;
- Socket client = null;
- try {
- serverSocket = new ServerSocket(9999);
- // 不断接收客户连接
- while (true) {
- // 服务器阻塞等待客户端 socket 连接过来
- client = serverSocket.accept();
- // ========= 请求类处理 =======
- InputStream in = client.getInputStream();
- HttpRequest request = new HttpRequest(in);
- String requestUri = request.getUri();
- // ========= 响应类处理 =======
- OutputStream os = client.getOutputStream();
- HttpResponse response = new HttpResponse(os);
- // 请求格式是 / html/login.html 这种, 需要把开头的 / 删除
- response.writerFile(requestUri.substring(1));
- client.close();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
测试结果如下:
在浏览器输入
http://localhost:9999/docs/ssl-howto.html
效果如下
你会惊奇的发现样式并不能识别, 因此我们对响应头的部分逻辑进行修改
将
- sb.append("HTTP/1.1 200 OK\n");
- sb.append("Content-Type: text/html; charset=UTF-8\n");
- sb.append("\n");
部分修改为
- if(path.endsWith("css")) {
- sb.append("HTTP/1.1 200 OK\n");
- sb.append("Content-Type: text/css; charset=UTF-8\n");
- sb.append("\n");
- }else {
- sb.append("HTTP/1.1 200 OK\n");
- sb.append("Content-Type: text/html; charset=UTF-8\n");
- sb.append("\n");
- }
继续启动测试, 效果如下
已经能够正常显示
总结
本文给出了两个版本的静态资源的服务器源码, 希望读者能够有所收获.
来源: https://www.cnblogs.com/rjzheng/p/8886298.html