Java网络编程从入门到精通(22):实现HTTP模拟器

本文涉及的产品
.cn 域名,1个 12个月
简介: 本文为原创,如需转载,请注明作者和出处,谢谢! 上一篇:Java网络编程从入门到精通(21):HTTP消息的格式 源代码和.class文件下载    在讨论HTTP协议的具体请求和响应头字段之前,让我们先来利用以前所学的知识来实现一个HTTP模拟器。

本文为原创,如需转载,请注明作者和出处,谢谢!

上一篇:Java网络编程从入门到精通(21):HTTP消息的格式

源代码和.class文件下载

    在讨论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方法用来运行这个程序。实现代码如下:

  001    package http;
  
002   
  
003    import  java.net. * ;
  
004    import  java.io. * ;
  
005   
  
006    public   class  HttpSimulator
  
007   {
  
008        private  Socket socket;
  
009        private   int  port  =   80 ;
  
010        private  String host  =   " localhost " ;
  
011        private  String request  =   "" //  HTTP请求消息
   012        private   boolean  isPost, isHead;
  
013        
  
014        public   void  run()  throws  Exception
  
015       {
  
016           BufferedReader reader  =   new  BufferedReader( new  InputStreamReader(
  
017                   System.in));
  
018            while  ( true )   //  开始大循环
   019           {
  
020                try
  
021               {
  
022                    if  ( ! readHostAndPort(reader))
  
023                        break ;
  
024                   readHttpRequest(reader);
  
025                   sendHttpRequest();
  
026                   readHttpResponse(reader);
  
027               }
  
028                catch  (Exception e)
  
029               {
  
030                   System.out.println( " err: "   +  e.getMessage());
  
031               }
  
032           }
  
033       }
  
034        public   static   void  main(String[] args)  throws  Exception
  
035       {
  
036            new  HttpSimulator().run();
  
037       }
  
038   }

从上面的代码可以看出,第022、024、025和026分别调用了上述的四个方法。这些方法的具体实现将在后面讨论。上面的代码除了调用这四个核心方法外,还做了一些准备工作。在008至012行定义了一些以后要用到的变量。在016和017行使用控制台的输入流建立了BufferedReader对象,通过这个对象,可以直接从控制台读取字符串,而不是一个个地字节。

二、readHostAndPort(...)
方法的实现

    这个方法的主要功能是从控制台读取域名和端口。域名和端口通过":"隔开,":"和域名以及端口之间不能有空格。当从控制台读取一个"q"时,这个函数返回false,表示程序可以退出了,否则返回true,表示输入的域名和端口是正确的。这个方法的实现代码如下:

   001    private   boolean  readHostAndPort(BufferedReader consoleReader)
  
002            throws  Exception
  
003   {
  
004       System.out.print( " host:port> " );
  
005       String[] ss  =   null ;
  
006       String s  =  consoleReader.readLine();
  
007        if  (s.equals( " q " ))
  
008            return   false ;
  
009        else
  
010       {
  
011           ss  =  s.split( " [:] " );
  
012            if  ( ! ss[ 0 ].equals( "" ))
  
013               host  =  ss[ 0 ];
  
014            if  (ss.length  >   1 )
  
015               port  =  Integer.parseInt(ss[ 1 ]);
  
016           System.out.println(host  +   " : "   +  String.valueOf(port));
  
017            return   true ;
  
018       }
  
019   }

第001行:这个方法有一个BufferedReader类型的参数,这个参数的值就是在HttpSimulator.java中的第016和017行根据控制台输入流建立的BufferedReader对象。

第 004 行:这输出HTTP模拟器的控制符,就象Windows的控制台的"C:">"一样。

第 006 行:从控制台读取一行字符串。

第 011 行:通过字符串的split方法和响应的正则表示式("[:]")将域名和端口分开。域名的默认值是localhost,端口的默认值是80。

三、readHttpRequest(...)
方法的实现

    这个方法的主要功能是从控制台读取HTTP请求消息,如果输入一个空行,表示请求消息头已经输完;如果使用的是POST方法,还要输入POST请求的实体内容。这个方法的实现代码如下:

   001    private   void  readHttpRequest(BufferedReader consoleReader) 
  
002            throws  Exception
  
003   {
  
004       System.out.println( " 请输入HTTP请求: " );
  
005       String s  =  consoleReader.readLine();
  
006       request  =  s  +   " /r/n " ;
  
007        boolean  isPost  =  s.substring( 0 4 ).equals( " POST " );
  
008        boolean  isHead  =  s.substring( 0 4 ).equals( " HEAD " );
  
009        while  ( ! (s  =  consoleReader.readLine()).equals( "" ))
  
010           request  =  request  +  s  +   " /r/n " ;
  
011       request  =  request  +   " /r/n " ;
  
012        if  (isPost)
  
013       {
  
014           System.out.println( " 请输入POST方法的内容: " );
  
015           s  =  consoleReader.readLine();
  
016           request  =  request  +  s;
  
017       }
  
018   }

第 005 行:读入HTTP请求消息的第一行。

第 007、008行:确定所输入的请求方法是不是POST和HEAD。

第 009、010行:读入HTTP请求消息的其余行。

第012 017行:如果HTTP请求使用的是POST方法,要求用户继续输入HTTP请求的实体内容。

四、sendHttpRequest()
方法的实现

    这个方法的功能是将request变量中的HTTP请求消息发送到服务器。下面是这个方法的实现代码:

   001        private   void  sendHttpRequest()  throws  Exception
  
002       {
  
003           socket  =   new  Socket();
  
004           socket.setSoTimeout( 10   *   1000 );
  
005           System.out.println( " 正在连接服务器 " );
  
006           socket.connect( new  InetSocketAddress(host, port),  10   *   1000 );
  
007           System.out.println( " 服务器连接成功! " );
  
008           OutputStream out  =  socket.getOutputStream();
  
009           OutputStreamWriter writer  =   new  OutputStreamWriter(out);
  
010           writer.write(request);
  
011           writer.flush();
  
012       }

第004行:设置读取数据超时为10秒。

第006行:连接服务器,并设置连接超时为10秒。

五、readHttpResponse(...)
方法的实现

这个方法的主要功能是从服务器读取返回的响应消息。首先读取了响应消息头,然后要求用户输入Y或N以确定是否显示响应消息的实体内容。这个程序之所以这样做,主要有两个原因:

(1) 为了研究HTTP协议。

(2) 由于本程序是以字符串形式显示响应消息的,因此,如果用户请求了一个二进制Web资源,如一个rar文件,那么实体内容将会显示乱码。所以在显示完响应消息头后由用户决定是否显示实体内容。

这个方法的实现代码如下:

   001    private   void  readHttpResponse(BufferedReader consoleReader)
  
002   {
  
003       String s  =   "" ;
  
004        try
  
005       {
  
006           InputStream in  =  socket.getInputStream();
  
007           InputStreamReader inReader  =   new  InputStreamReader(in);
  
008           BufferedReader socketReader  =   new  BufferedReader(inReader);
  
009           System.out.println( " ---------HTTP头--------- " );
  
010            boolean  b  =   true //  true: 未读取消息头 false: 已经读取消息头
   011            while  ((s  =  socketReader.readLine())  !=   null )
  
012           {
  
013                if  (s.equals( "" &&  b  ==   true   &&   ! isHead)
  
014               {
  
015                   System.out.println( " ------------------------ " );
  
016                   b  =   false ;
  
017                   System.out.print( " 是否显示HTTP的内容(Y/N): " );
  
018                   String choice  =  consoleReader.readLine();
  
019                    if  (choice.equals( " Y " ||  choice.equals( " y " ))
  
020                   {
  
021                       System.out.println( " ---------HTTP内容--------- " );
  
022                        continue ;
  
023                   }
  
024                    else
  
025                        break ;
  
026               }
  
027                else
  
028                   System.out.println(s);
  
029           }
  
030       }
  
031        catch  (Exception e)
  
032       {
  
033           System.out.println( " err: "   +  e.getMessage());
  
034       }
  
035        finally
  
036       {
  
037            try
  
038           {
  
039               socket.close();
  
040           }
  
041            catch  (Exception e)
  
042           {
  
043           }
  
044       }
  
045       System.out.println( " ------------------------ " );
  
046   }

在上面的代码中013行是最值得注意的。其中s.equals("")表示读入一个空行(表明消息头已经结束);由于在实体内容中也可以存在空行,因此,b == true来标记消息头是否已经被读过,当读完消息头后,将b设为false,如果以后再遇到空行,就不会当成消息头来处理了。当HTTP请求使用HEAD方法时,服务器只返回响应消息头;因此,使用!isHead来保证使用HEAD发送请求时不显示响应消息的内容实体。

现在我们已经实现了这个HTTP模拟器,下面让我们来运行并测试它。

 运行

运行如下的命令

java http.HttpSimulator    

    运行以上的命令后,将显示如图1所示的界面。

图1

测试

在HTTP模拟器中输入如下的域名:

www.csdn.net

在HTTP模拟器中输入如下的HTTP请求消息:

GET  /  HTTP / 1.1
Host: www.csdn.net

运行的结果如图2所示。


图2

本文实现的Http模拟器在后面的文章中会经常使用,读者可以从本文的开始部分下载Http模拟器的源代码和.class文件。

下一篇: Java网络编程从入门到精通(23):HTTP消息头字段

国内最棒的Google Android技术社区(eoeandroid),欢迎访问!

《银河系列原创教程》发布

《Java Web开发速学宝典》出版,欢迎定购

目录
相关文章
|
11天前
|
监控 安全 数据安全/隐私保护
智能家居安全入门:保护你的网络家园
本文旨在为初学者提供一份简明扼要的指南,介绍如何保护自己的智能家居设备免受网络攻击。通过分析智能家居系统常见的安全漏洞,并提供实用的防御策略,帮助读者建立起一道坚固的数字防线。
|
12天前
|
图形学 C#
超实用!深度解析Unity引擎,手把手教你从零开始构建精美的2D平面冒险游戏,涵盖资源导入、角色控制与动画、碰撞检测等核心技巧,打造沉浸式游戏体验完全指南
【8月更文挑战第31天】本文是 Unity 2D 游戏开发的全面指南,手把手教你从零开始构建精美的平面冒险游戏。首先,通过 Unity Hub 创建 2D 项目并导入游戏资源。接着,编写 `PlayerController` 脚本来实现角色移动,并添加动画以增强视觉效果。最后,通过 Collider 2D 组件实现碰撞检测等游戏机制。每一步均展示 Unity 在 2D 游戏开发中的强大功能。
52 6
|
12天前
|
算法 Java 开发者
Java 编程入门:从零到一的旅程
本文将带领读者开启Java编程之旅,从最基础的语法入手,逐步深入到面向对象的核心概念。通过实例代码演示,我们将一起探索如何定义类和对象、实现继承与多态,并解决常见的编程挑战。无论你是编程新手还是希望巩固基础的开发者,这篇文章都将为你提供有价值的指导和灵感。
|
3天前
|
机器学习/深度学习 人工智能 TensorFlow
神经网络入门到精通:Python带你搭建AI思维,解锁机器学习的无限可能
【9月更文挑战第10天】神经网络是开启人工智能大门的钥匙,不仅是一种技术,更是模仿人脑思考的奇迹。本文从基础概念入手,通过Python和TensorFlow搭建手写数字识别的神经网络,逐步解析数据加载、模型定义、训练及评估的全过程。随着学习深入,我们将探索深度神经网络、卷积神经网络等高级话题,并掌握优化模型性能的方法。通过不断实践,你将能构建自己的AI系统,解锁机器学习的无限潜能。
9 0
|
12天前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的卷积神经网络(CNN)入门
【8月更文挑战第31天】在人工智能的浪潮中,深度学习以其强大的数据处理能力成为时代的宠儿。本文将引导你走进深度学习的核心组件之一——卷积神经网络(CNN),并带你一探其背后的奥秘。通过简明的语言和直观的代码示例,我们将一起构建一个简易的CNN模型,理解它在图像处理领域的应用,并探索如何利用Python和TensorFlow实现它。无论你是初学者还是有一定基础的开发者,这篇文章都将为你打开一扇通往深度学习世界的大门。
|
12天前
|
Java 程序员 UED
Java 中的异常处理:从入门到精通
【8月更文挑战第31天】在Java编程的世界中,异常处理是保持应用稳定性的重要机制。本文将引导你理解异常的本质,学会如何使用try-catch语句来捕获和处理异常,并探索自定义异常类的魅力。我们将一起深入异常的世界,让你的代码更加健壮和用户友好。
|
12天前
|
机器学习/深度学习 人工智能 TensorFlow
深度学习入门:使用Python和TensorFlow构建你的第一个神经网络
【8月更文挑战第31天】 本文是一篇面向初学者的深度学习指南,旨在通过简洁明了的语言引导读者了解并实现他们的第一个神经网络。我们将一起探索深度学习的基本概念,并逐步构建一个能够识别手写数字的简单模型。文章将展示如何使用Python语言和TensorFlow框架来训练我们的网络,并通过直观的例子使抽象的概念具体化。无论你是编程新手还是深度学习领域的新兵,这篇文章都将成为你探索这个激动人心领域的垫脚石。
|
12天前
|
机器学习/深度学习 自动驾驶 算法框架/工具
深度学习中的卷积神经网络(CNN)入门
【8月更文挑战第31天】 本文旨在通过浅显易懂的方式,引导初学者步入卷积神经网络(CNN)的神秘世界。我们将从CNN的基础概念出发,逐步深入到其在图像处理中的应用实例,最后通过一个简单的Python代码示例,展示如何实现一个基础的CNN模型。无论你是编程新手还是深度学习领域的初探者,这篇文章都将为你打开一扇了解和掌握CNN的大门。
|
12天前
|
Java 数据库连接 开发者
Java中的异常处理:从入门到精通
【8月更文挑战第31天】 在编程世界中,错误和异常就像是不请自来的客人,总是在不经意间打扰我们的程序运行。Java语言通过其异常处理机制,为开发者提供了一套优雅的“待客之道”。本文将带你走进Java异常处理的世界,从基础语法到高级技巧,再到最佳实践,让你的程序在面对意外时,也能从容不迫,优雅应对。
|
12天前
|
机器学习/深度学习 人工智能 算法
深度学习中的卷积神经网络(CNN)入门
【8月更文挑战第31天】 在探索人工智能的奥秘时,我们常常被其背后的复杂算法所迷惑。本文旨在以浅显易懂的语言,带你走进深度学习的世界,特别是卷积神经网络(CNN)这一核心概念。我们将一起了解CNN的基本结构,它是如何工作的,以及为什么它在图像识别领域如此强大。通过简单的代码示例,你将学会如何搭建一个简单的CNN模型,并在自己的数据集上进行实验。无论你是编程新手还是深度学习初学者,这篇文章都将为你打开一扇通往高级人工智能应用的大门。

热门文章

最新文章