美文网首页
Java模拟B/S服务器实战

Java模拟B/S服务器实战

作者: Patarw | 来源:发表于2020-08-16 11:58 被阅读0次

    一、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请求:

    可以看到返回的是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:由于指定一种自然语言。

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

    显然,我们需要使用到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页面显示出来了:

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

    相关文章

      网友评论

          本文标题:Java模拟B/S服务器实战

          本文链接:https://www.haomeiwen.com/subject/quctjktx.html