- 浏览: 5207 次
- 性别:
- 来自: 杭州
文章分类
最新评论
在讨论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 }
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(...) 方法的实现
二、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 }
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(...) 方法的实现
三、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 }
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() 方法的实现
四、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 }
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(...) 方法的实现
五、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 }
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
Host: www.csdn.net
运行的结果如图2所示。
图2
本文实现的Http模拟器在后面的文章中会经常使用,读者可以从本文的开始部分下载Http模拟器的源代码和.class文件。发表评论
-
Java网络编程从入门到精通(33):非阻塞I/O的缓冲区(Buffer)
2011-08-03 17:04 916如果将同步 I/O方式下的数据传输比做数据传输的零星方 ... -
Java网络编程从入门到精通(31):非阻塞I/O简介
2011-08-03 17:01 713在网络应用中,一般可以采用同步 I/O(阻塞 I/O)和非 ... -
用Java的Socket加IO流模拟FTP功能
2011-08-03 16:58 1872最近学习java编程是一个实验让我困惑了很久就是: 编写 ... -
Java网络编程从入门到精通(19):套接字(Socket)的异常
2011-08-03 16:56 894在Socket类中有很多方法在声明时使用throws抛出了一些 ...
相关推荐
### JAVA网络编程从入门到精通知识点详解 #### 一、Internet地址概述 互联网中的每一台设备都需要有一个唯一的标识符——IP地址。当前广泛使用的IPv4地址由四个字节组成,而未来的趋势是采用16个字节的IPv6地址。 ...
"Android开发从入门到精通光盘源代码"是一个很好的学习资源,提供了随书配套的详细代码示例,帮助开发者深入理解Android应用开发的各个环节。这里我们将围绕这个主题,深入探讨Android开发中的关键知识点。 首先,...
在Android开发领域,掌握基础知识是至关重要的,而这套"Android开发从入门到精通【视频教程+课程源码】"提供了一条系统学习的路径。它不仅包括了详细的视频讲解,还有配套的源代码,旨在帮助初学者从零开始,逐步...
**J2ME从入门到精通** Java Micro Edition(J2ME)是Java平台的一个子集,主要用于嵌入式系统和移动设备,如早期的智能手机、电视盒和家用电器。本教程将带你逐步深入J2ME的世界,理解其基本概念、开发环境搭建、...
Android开发从入门到精通是扶松柏编著的一本关于Android应用程序开发的书籍。该书面向初学者,旨在通过简洁明了的语言和生动的实例,详细介绍Android应用开发中所需掌握的各种技术。书中可能覆盖的内容包括但不限于...
《Android开发从入门到精通》是一本专门为Android编程新手量身打造的教程。这本书全面覆盖了Android开发的基础知识,旨在帮助读者快速掌握Android应用开发的核心技能。以下是对书中的主要知识点进行的详细解读: 1....
《Android开发从入门到精通》是一本针对Android Studio的详细开发指南,旨在帮助初学者和有一定基础的开发者深入了解和掌握Android应用开发的核心技术。在学习Android开发的过程中,Android Studio是官方推荐的集成...
### Android开发编程从入门到精通——Android程序员必备 #### 一、什么是Android及发展历程 - **定义**:Android是一种基于Linux内核的操作系统,主要用于移动设备如智能手机和平板电脑等。 - **历史背景**: - ...
根据提供的信息,《Android移动应用开发从入门到精通》这本书由张魏和李卉共同编写,主要面向希望学习或深入理解Android应用开发的技术人员、学生以及对移动应用开发感兴趣的读者。以下是从该书标题、描述及部分提及...
《Unity 5.x从入门到精通》是一本专业的教材,旨在帮助初学者和有经验的开发者更好地理解和掌握Unity引擎的各个方面。 这本书的配套光盘资源提供了丰富的实例和教程,旨在通过实践来加强理论学习。这些资源包括但不...
《Android开发从入门到精通》是一本针对Android初始开发学习人员的专业书籍,由扶松柏编写,由北京希望电子出版社出版。这本书深入浅出地讲解了Android开发的基础知识和核心技能,适合于对Android开发感兴趣的读者...
"Android从入门到精通"的课程不仅包含上述基础内容,还会逐步引导你进入更高级的主题,如多线程、网络编程、数据库操作、第三方库的使用、Android自定义View的开发,甚至是最新的Android版本特性。通过深入学习和...
《Android从入门到精通》是一本全面覆盖Android开发基础到高级技术的教程,旨在帮助初学者及有一定经验的开发者深入理解和掌握Android应用开发的核心技能。这本书涵盖了从安装Android开发环境,编写第一个Hello ...
在本段信息中,提到的是《Android移动应用开发从入门到精通》一书,作者是张魏和李。这本书显然是关于Android移动应用开发的教程,从基础入门讲起,逐步深入到精通级别,适合想要学习Android应用开发的读者。 ...
根据提供的标题“Android开发应用从入门到精通.pdf”和描述“pdf的资源清晰度还不错,有些存在排版有问题,请谨慎下载”,我们可以推断出这份PDF文档涵盖了从基础到高级的Android应用程序开发技术。下面将围绕...
这个“Android Studio从入门到精通.zip”压缩包显然是一个全面的学习资源,旨在帮助初学者理解并掌握Android Studio的使用。 Android Studio的核心特性包括: 1. **智能代码编辑器**:它提供了代码补全、语法高亮、...
### Android从入门到精通 #### 一、Android概述 ##### 1.1 什么是Android Android是一种基于Linux内核(不包含GNU组件)的开源移动操作系统,由Google公司和开放手机联盟领导及开发。Android主要应用于移动设备,...
"Android游戏开发从入门到精通"的主题旨在为开发者提供一套全面的学习路径,从基础概念到高级技术,帮助他们掌握创建引人入胜的移动游戏所需的知识。 首先,Android游戏开发的基础是Java或Kotlin编程语言,这两种...
### Android从入门到精通SL(实例源程序) #### 一、Android基础知识 1. **Android系统简介** - Android是一个基于Linux内核的开源移动操作系统,由Google公司维护。 - 它支持多种设备,包括智能手机、平板电脑...
《Android移动应用开发从入门到精通》这本书是针对Android移动应用开发领域的一本实用指南。在介绍这本书之前,我们需要了解Android平台的基础知识以及移动应用开发的相关概念。 首先,Android是一种基于Linux内核...