Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 489|回复: 0

[网络编程学习]Java网络编程从入门到精通(22)HTTP模拟器

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-11-4 00:02:21 | 显示全部楼层 |阅读模式
    在讨论HTTP协议的具体请求和响应头字段之前,让我们先来利用以前所学的知识来实现一个HTTP模拟器。所谓HTTP模拟器就是可以在用户输入HTTP 的请求消息后,由这个模拟器将HTTP请求发送给相应的服务器,再接收服务器的响应消息。这个HTTP模拟器有几下特点:

    1. 可以手工输入HTTP请求,并向服务器发送。

    2. 接收服务器的响应消息。

    3. 消息头和实体内容分段显示,也就是说,并不是象Telnet等客户端一样将HTTP响应消息全部显示,而是先显示消息头,然后由用户决定是否显示实体内容。

    4. 集中发送请求。这个HTTP模拟器和Telnet不同的是,并不是一开始就连接服务器,
    而是将域名、端口以及HTTP请求消息都输完后,才连接服务器,并将这些请求发送给服务器。这样做的可以预防服务器提前关闭网络连接的现象。  
      
       
       
         
       

         
       
      
    5. 可以循环做上述的操作。
    从以上的描述看,要实现这个HTTP模拟器需要以下五步:

    1. 建立一个大循环,在循环内部是一个请求/响应对。这样就可以向服务器发送多次请求/响应以了。下面的四步都是被包括在循环内部的。

    2. 从控制台读取域名和端口,这个功能可以由readHostAndPort(...)来完成。

    3. 从控制台读取HTTP请求消息,这个功能由readHttpRequest(...)来完成。

    4. 向服务器发送HTTP请求消息,这个功能由sendHttpRequest()来完成。

    5. 读取服务器回送的HTTP响应消息,这个功能由readHttpResponse(...)来完成。
    下面我们就来逐步实现这五步:

    一、建立一个大循环
    在建立这个循环之前,先建立一个中叫HttpSimulator的类,并在这个类中定义一个run方法用来运行这个程序。实现代码如下:
    1. package http;

    2. import java.net.*;
    3. import java.io.*;
    4.   
    5. public class HttpSimulator
    6.   {
    7.       private Socket socket;
    8.       private int port = 80;
    9.       private String host = "localhost";
    10.       private String request = ""; // HTTP请求消息
    11.       private boolean isPost, isHead;
    12.       ......
    13.       public void run() throws Exception
    14.       {
    15.           BufferedReader reader = new BufferedReader(new InputStreamReader( System.in));
    16.           while (true)  // 开始大循环
    17.           {
    18.               try
    19.               {
    20.                   if (!readHostAndPort(reader))
    21.                       break;
    22.                   readHttpRequest(reader);
    23.                   sendHttpRequest();
    24.                   readHttpResponse(reader);
    25.               }
    26.               catch (Exception e)
    27.               {
    28.                   System.out.println("err:" + e.getMessage());
    29.               }
    30.           }
    31.       }
    32.       public static void main(String[] args) throws Exception
    33.       {
    34.           new HttpSimulator().run();
    35.       }
    36.   }
    复制代码
    从上面的代码可以看出,分别调用了上述的四个方法。这些方法的具体实现将在后面讨论。上面的代码除了调用这四个核心方法外,还做了一些准备工作。定义了一些以后要用到的变量。建立了BufferedReader对象,通过这个对象,可以直接从控制台读取字符串,而不是一个个地字节。 二、 readHostAndPort(...)方法的实现
         这个方法的主要功能是从控制台读取域名和端口。域名和端口通过":"隔开,":"和域名以及端口之间不能有空格。当从控制台读取一个"q"时,这个函数返回false,表示程序可以退出了,否则返回true,表示输入的域名和端口是正确的。这个方法的实现代码如下:
    1.   001 private boolean readHostAndPort(BufferedReader consoleReader)
    2.   002          throws Exception
    3.   003  {
    4.   004      System.out.print("host:port>");
    5.   005      String[] ss = null;
    6.   006      String s = consoleReader.readLine();
    7.   007      if (s.equals("q"))
    8.   008          return false;
    9.   009      else
    10.   010      {
    11.   011          ss = s.split("[:]");
    12.   012          if (!ss[0].equals(""))
    13.   013              host = ss[0];
    14.   014          if (ss.length > 1)
    15.   015              port = Integer.parseInt(ss[1]);
    16.   016          System.out.println(host + ":" + String.valueOf(port));
    17.   017          return true;
    18.   018      }
    19.   019  }
    复制代码
    第 001行:这个方法有一个 BufferedReader类型的参数,这个参数的值就是在HttpSimulator.java中的第016和017行根据控制台输入流建立的 BufferedReader对象。
    第 004 行:这输出HTTP模拟器的控制符,就象Windows的控制台的"C:">"一样。
    第 006 行:从控制台读取一行字符串。
    第 011 行:通过字符串的split方法和响应的正则表示式("[:]")将域名和端口分开。域名的默认值是localhost,端口的默认值是80。 三、readHttpRequest(...)方法的实现
       这个方法的主要功能是从控制台读取HTTP请求消息,如果输入一个空行,表示请求消息头已经输完;如果使用的是POST方法,还要输入POST请求的实体内容。这个方法的实现代码如下:
    1.   001  private void readHttpRequest(BufferedReader consoleReader)
    2.   002          throws Exception
    3.   003  {
    4.   004      System.out.println("请输入HTTP请求:");
    5.   005      String s = consoleReader.readLine();
    6.   006      request = s + "
    7. ";
    8.   007      boolean isPost = s.substring(0, 4).equals("POST");
    9.   008      boolean isHead = s.substring(0, 4).equals("HEAD");
    10.   009      while (!(s = consoleReader.readLine()).equals(""))
    11.   010          request = request + s + "
    12. ";
    13.   011      request = request + "
    14. ";
    15.   012      if (isPost)
    16.   013      {
    17.   014          System.out.println("请输入POST方法的内容:");
    18.   015          s = consoleReader.readLine();
    19.   016          request = request + s;
    20.   017      }
    21.   018  }
    复制代码
    第 005 行:读入HTTP请求消息的第一行。
    第 007、008行:确定所输入的请求方法是不是POST和HEAD。
    第 009、010行:读入HTTP请求消息的其余行。
    第012 ? 017行:如果HTTP请求使用的是POST方法,要求用户继续输入HTTP请求的实体内容。 四、sendHttpRequest()方法的实现
    这个方法的功能是将request变量中的HTTP请求消息发送到服务器。下面是这个方法的实现代码:
    1.   001      private void sendHttpRequest() throws Exception
    2.   002      {
    3.   003          socket = new Socket();
    4.   004          socket.setSoTimeout(10 * 1000);
    5.   005          System.out.println("正在连接服务器");
    6.   006          socket.connect(new InetSocketAddress(host, port), 10 * 1000);
    7.   007          System.out.println("服务器连接成功!");
    8.   008          OutputStream out = socket.getOutputStream();
    9.   009          OutputStreamWriter writer = new OutputStreamWriter(out);
    10.   010          writer.write(request);
    11.   011          writer.flush();
    12.   012      }
    复制代码
    第 004行:设置读取数据超时为10秒。
    第006行:连接服务器,并设置连接超时为10秒。 五、readHttpResponse(...)方法的实现
        这个方法的主要功能是从服务器读取返回的响应消息。首先读取了响应消息头,然后要求用户输入Y或N以确定是否显示响应消息的实体内容。这个程序之所以这样做,主要有两个原因:

    (1) 为了研究HTTP协议。

    (2) 由于本程序是以字符串形式显示响应消息的,因此,如果用户请求了一个二进制Web资源,如一个rar文件,那么实体内容将会显示乱码。所以在显示完响应消息头后由用户决定是否显示实体内容。
    这个方法的实现代码如下:
    1.   001  private void readHttpResponse(BufferedReader consoleReader)
    2.   002  {
    3.   003      String s = "";
    4.   004      try
    5.   005      {
    6.   006          InputStream in = socket.getInputStream();
    7.   007          InputStreamReader inReader = new InputStreamReader(in);
    8.   008          BufferedReader socketReader = new BufferedReader(inReader);
    9.   009          System.out.println("---------HTTP 头---------");
    10.   010          boolean b = true; // true: 未读取消息头 false: 已经读取消息头
    11.   011          while ((s = socketReader.readLine()) != null)
    12.   012          {
    13.   013              if (s.equals("") && b == true && !isHead)
    14.   014              {
    15.   015                  System.out.println("------------------------");
    16.   016                  b = false;
    17.   017                  System.out.print("是否显示HTTP的内容 (Y/N):");
    18.   018                  String choice = consoleReader.readLine();
    19.   019                  if (choice.equals("Y") || choice.equals("y"))
    20.   020                  {
    21.   021                      System.out.println("---------HTTP 内容---------");
    22.   022                      continue;
    23.   023                  }
    24.   024                  else
    25.   025                      break;
    26.   026              }
    27.   027              else
    28.   028                  System.out.println(s);
    29.   029          }
    30.   030      }
    31.   031      catch (Exception e)
    32.   032      {
    33.   033          System.out.println("err:" + e.getMessage());
    34.   034      }
    35.   035      finally
    36.   036      {
    37.   037          try
    38.   038          {
    39.   039              socket.close();
    40.   040          }
    41.   041          catch (Exception e)
    42.   042          {
    43.   043          }
    44.   044      }
    45.   045      System.out.println("------------------------");
    46.   046  }
    复制代码
       在上面的代码中 013行是最值得注意的。其中s.equals("")表示读入一个空行(表明消息头已经结束);由于在实体内容中也可以存在空行,因此,b == true来标记消息头是否已经被读过,当读完消息头后,将b设为false,如果以后再遇到空行,就不会当成消息头来处理了。当HTTP请求使用HEAD 方法时,服务器只返回响应消息头;因此,使用!isHead来保证使用HEAD发送请求时不显示响应消息的内容实体。

    现在我们已经实现了这个HTTP模拟器,下面让我们来运行并测试它。
    运行
    运行如下的命令
    java http.HttpSimulator
    运行以上的命令后,将显示如图1所示的界面。



    测试
    在 HTTP模拟器中输入如下的域名:
    www.csdn.net
    在 HTTP模拟器中输入如下的HTTP请求消息:
    GET / HTTP/1.1
    Host: www.csdn.net
    运行的结果如图2所示。






      
      
       
       

         
       

         
       
      
    复制代码

    源码下载:http://file.javaxxz.com/2014/11/4/000221187.rar
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-25 13:31 , Processed in 0.355283 second(s), 36 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表