Java模拟B/S服务器实战

一、B/S网络架构概述

  • 全称Browser/Server结构,是浏览器/服务器结构,就是我们经常利用浏览器进行访问,常见的有chrome,Firefox,IE等等,都基于统一的应用层协议HTTP来交互数据。
  • HTTP采用无状态的短连接的通信方式,通常情况下,一次请求完成了一次数据交互,然后这次通信连接就断开了。这种方式的好处是能够让服务器处理海量用户的访问请求。

二、如何发起一个HTTP请求

  • 当你在浏览器中输入一个URL时,按回车键后这个HTTP请求就发起了
  • 如何发起一个HTTP请求和如何建立一个Socket连接区别不大,只不过outputStream.write写的二进制数据格式要符合HTTP。(建议先去了解Java的I/O流后再来看这篇文章)浏览器在建立Socket连接之前,必须根据地址栏内输入的URL域名DNS解析出IP地址,在根据这个IP地址和默认的端口号80与远程服务器建立Socket连接,然后浏览器根据这个URL组装成一个get类型的HTTP请求头,通过outputStream.write发送到目标服务器,服务器等待inputStream.read返回数据,最后断开这个连接。
    一句话,发起一个HTTP请求的过程就是建立一个Socket通信的过程

你可以使用Linux中的curl指令来发送一个简单的HTTP请求:

Java模拟B/S服务器实战_第1张图片

可以看到返回的是html格式的代码

接下来我们要用Java代码来模拟B/S服务器,来了解服务器在接受到请求后做了哪些操作

三、通过java来模拟B/S服务器

首先来看看我们从浏览器请求一个网址我们的后台会收到什么:

  • 创建一个服务器代码:
    public static void main(String[] args) {
    try {
        //创建一个服务器ServerSocket,并指定端口号8088
        ServerSocket server = new ServerSocket(8088);
        //使用accept方法获取到请求的客户端对象(浏览器)
        Socket socket = server.accept();
        //使用socket对象中的方法getInputStream获取到网络字节输入流InputStream对象
        InputStream is = socket.getInputStream();
        //把网络字节输入流转换为字符缓冲输入流
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        
        //把客户端(浏览器)的请求信息打印出来
        String line = br.readLine();            
        while(line != null) {
        System.out.println(line);
         line = br.readLine();
        }

        socket.close();
        server.close();
    } catch (IOException e) {       
        e.printStackTrace();
    }

}
  • 先运行代码,然后再请求一个网址,假如我请求的是这个网址:

发现打印了一些HTTP请求头(HTTP Header),我这里只介绍一些常用的请求头

  • 从第一行我们可以看出我们发送的是一个GET请求,请求的路径为 /src/index.html ,使用的协议为 HTTP/1.1
  • Host:表示被请求资源的Internet主机和端口号,如 Host:www.taobao.com,也就是运行着这个程序的这台电脑,,这里的ip为localhost,端口号为8088;
  • Connection:表示当前连接是否保持,keep-alive 表示保持连接;
  • Cache-Control:表示是否缓存,这个有好几种缓存方式,max-age=xxx表示缓存的内容在xxx秒后失效,其他的几种我就不一细说了,感兴趣的可以自己去了解一下;
  • User-Agent:表示客户端(浏览器)将它的操作系统、浏览器和其他属性告诉服务器;
  • Accept-Encoding:表示指定可接受的内容编码;
  • Accept-Language:由于指定一种自然语言。
Java模拟B/S服务器实战_第2张图片

那么怎么模拟服务器在接收到这些请求后返回指定路径的资源呢,假定src目录下创建了一个index.html文件,那么要怎样才能返回这个资源从而让客户端(浏览器)访问到这个资源呢

Java模拟B/S服务器实战_第3张图片

显然,我们需要使用到Java中的 I/O操作, I/O 可以说是机器获取和交换信息的主要渠道,如何优化 I/O 也是目前Web应用中面临的主要问题,那么我们先来了解一些基本的 I/O 操作类吧,方便更好的理解我们之后要做的一系列操作。

  • 基于字符操作的 I/O 接口:InputStream 和OutputStream。
  • 基于字符操作的 I/O 接口:Writer 和 Reader。
  • 基于磁盘操作的 I/O 接口:File。
  • 基于网络操作的 I/O 接口:Socket。
  • 代码实现:
 public static void main(String[] args) {
    try {
        //创建一个服务器ServerSocket,并指定端口号8088
        ServerSocket server = new ServerSocket(8088);
        //使用accept方法获取到请求的客户端对象(浏览器)
        Socket socket = server.accept();
        //使用socket对象中的方法getInputStream获取到网络字节输入流InputStream对象
        InputStream is = socket.getInputStream();
        //把网络字节输入流转换为字符缓冲输入流
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        
                
        //这里我们只需要第一行就行了 GET /src/index.html HTTP/1.1
        String line = br.readLine();    
        //截取到中间的路径 /src/index.html,赋给htmlpath
        String[] arr = line.split(" ");
        String htmlpath = arr[1].substring(1);
        
        //创建一个文件输出流,读取服务器上该路径的文件信息
        FileInputStream fis = new FileInputStream(htmlpath);
        //使用socket对象中的方法getOutputStream获取到网络字节输出流OutputStream对象
        OutputStream os = socket.getOutputStream();
        
        //写入HTTP响应头,固定写法
        os.write("HTTP/1.1 200 OK\r\n".getBytes());         
        os.write("Content-type:text/html\r\n".getBytes());          
        os.write("\r\n".getBytes());
        
        //一读一写复制文件,把服务器读取的html文件回写到客户端(浏览器)
        int len = 0;
        byte[] bytes = new byte[1024];
        
        while((len = fis.read(bytes)) != -1) {
            os.write(bytes,0,len);
        }
        
        //释放资源
        fis.close();
        socket.close();
        server.close();
    } catch (IOException e) {       
        e.printStackTrace();
    }

}

运行我们的代码,再次到浏览器上访问这个网址:

可以看到我们的index.html页面显示出来了:

Java模拟B/S服务器实战_第4张图片

从浏览器的调试工具中也能看到各种信息,Request Headers是我们浏览器向服务器请求数据的请求头,这个前面已经介绍过了;Response Headers是服务器返回给浏览器的响应头,里面的 Content-Type 可以用来指明发送给浏览器的实体正文的媒体类型,还有很多其他的响应头,这里我也不一介绍了。

Java模拟B/S服务器实战_第5张图片

你可能感兴趣的:(Java模拟B/S服务器实战)