`
vivid_gxp
  • 浏览: 18994 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

Http协议客户端的JAVA简单实现 [转载]

阅读更多
import java.net.*;

import java.io.*;

import java.util.Properties;

import java.util.Enumeration;


/**

Http客户端程序已集成在Java语言中,可以通过URLConnection类调用。遗憾的

是,由于SUN没有公布Http客户程序的源码,它实现的细节仍是一个谜。本文根据HTTP

协议规范,用Java.net.Socket类实现一个HTTP协议客户端程序.


<pre>


1.Socket类:

了解TCP/IP协议集通信的读者知道,协议间的通信是通过Socket完成的。在

Java.net包中,Socket类就是对Socket的具体实现。它通过连接到主机后,返回一个

I/O流,实现协议间的信息交换。


2 . HTTP协议

HTTP协议同其它TCP/IP协议集中的协议一样,是遵循客户/服务器模型工作的。客

户端发往服务端的信息格式如下:

------------------------------

请求方法 URL HTTP协议的版本号

提交的元信息

**空行**

实体

------------------------------

请求方法是对这次连接工作的说明,目前HTTP协议已经发展到1.1版,它包括GET、

HEAD、POST、DELETE、OPTIONS、TRACE、PUT七种。元信息是关于当前请求的信息。通

过分析元信息,可以检查实体数据是否完整,接收过程是否出错,类型是否匹配等。元

信息的引入使HTTP协议通信更加稳妥可靠。实体是请求的具体内容。

将上述报文发往Web服务器,如果成功,应答格式如下:

--------------------------------

HTTP协议的版本号 应答状态码 应答状态码说明

接收的元信息

**空行**

实体

--------------------------------

以上报文发向客户端,并且接收成功,彼此间关闭连接,完成一次握手。

下面用最常用的GET方法,来说明具体的报文应用

----------------------------------

GET http://www.youhost.com HTTP/1.0

accept: www/source; text/html; image/gif; image/jpeg; */*

User_Agent: myAgent

**空行**

-----------------------------------

这个报文是向www.youhost.com主机请求一个缺省HTML文档。客户端HTTP协议版本

号是1.0版,元信息包括可接收的文件格式,用户代理,每一段之间用回车换行符分

隔,最后以一个空行结束。发向服务器后,如果执行过程正常,服务器返回以下代码:

------------------------------------

HTTP/1.1 200 OK

Date: Tue, 14 Sep 1999 02:19:57 GMT

Server: Apache/1.2.6

Connection: close

Content-Type: text/html

**空行**

<html><head>...</head><body>...</body></html>

------------------------------------

HTTP/1.1表示这个HTTP服务器是1.1版,200是服务器对客户请求的应答状态码,OK

是对应答状态码的解释,之后是这个文档的元信息和文档正文。(相关应答状态码和元

信息的解释请参阅Inetrnet标准草案:RFC2616)。


注: 程序中只实现GET、HEAD、POST三种方法。其他几种因不常使用,暂且忽略。


</pre>


*/

public class Http{

    protected Socket client;

    protected BufferedOutputStream sender;

    protected BufferedInputStream receiver;

    protected ByteArrayInputStream byteStream;

    protected URL target;

    private int responseCode = -1;

    private String responseMessage = "";

    private String serverVersion = "";

    private Properties header = new Properties();


    public Http(){}


    public Http(String url){

        GET(url);

    }


    /* GET方法根据URL,会请求文件、数据库查询结果、程序运行结果等多种内容 */

    public void GET(String url){

        try{

            checkHTTP(url);

            openServer(target.getHost(),target.getPort());

            String cmd = "GET " + getURLFormat(target) + " HTTP/1.0\r\n" +

            getBaseHeads() + "\r\n";

            sendMessage(cmd);

            receiveMessage();

        }

        catch(ProtocolException p){

            p.printStackTrace();

            return;

        }

        catch(UnknownHostException e){

            e.printStackTrace();

            return;

        }

        catch(IOException i){

            i.printStackTrace();

            return;

        }

    }


    /*

     * HEAD方法只请求URL的元信息,不包括URL本身。若怀疑本机和服务器上的

     * 文件相同,用这个方法检查最快捷有效。

     */

    public void HEAD(String url){

        try{

            checkHTTP(url);

            openServer(target.getHost(),target.getPort());

            String cmd = "HEAD " + getURLFormat(target) + " HTTP/1.0\r\n" +

            getBaseHeads() + "\r\n";

            sendMessage(cmd);

            receiveMessage();

        }

        catch(ProtocolException p){

            p.printStackTrace();

            return;

        }

        catch(UnknownHostException e){

            e.printStackTrace();

            return;

        }

        catch(IOException i){

            i.printStackTrace();

            return;

        }

    }


    /*

     * POST方法是向服务器传送数据,以便服务器做出相应的处理。例如网页上常用的

     * 提交表格。

     */

    public void POST(String url,String content){

        try{

            checkHTTP(url);

            openServer(target.getHost(),target.getPort());

            String cmd = "POST " + getURLFormat(target) + " HTTP/1.0\r\n" +

            getBaseHeads();

            cmd += "Content-type: application/x-www-form-urlencoded\r\n";

            cmd += "Content-length: " + content.length() + "\r\n\r\n";

            cmd += content + "\r\n";

            sendMessage(cmd);

            receiveMessage();

        }

        catch(ProtocolException p){

            p.printStackTrace();

            return ;

        }

        catch(UnknownHostException e){

            e.printStackTrace();

            return ;

        }

        catch(IOException i){

            i.printStackTrace();

            return ;

        }


    }


    protected void checkHTTP(String url) throws ProtocolException{

        try{

            URL target = new URL(url);

            if(target == null ||

               !target.getProtocol().toUpperCase().equals("HTTP")){

                throw new ProtocolException("这不是HTTP协议");

            }

            this.target = target;

        }

        catch(MalformedURLException m){

            throw new ProtocolException("协议格式错误");

        }

    }


    /*

     * 与Web服务器连接。若找不到Web服务器,InetAddress会引发UnknownHostException

     * 异常。若Socket连接失败,会引发IOException异常。

     */

    protected void openServer(String host,int port) throws UnknownHostException,

    IOException{

        header.clear();

        responseMessage = "";

        responseCode = -1;


        if(client != null){

            closeServer();

        }

        if(byteStream != null){

            byteStream.close();

            byteStream = null;

        }


        InetAddress address = InetAddress.getByName(host);

        client = new Socket(address,port == -1 ? 80 : port);

        client.setSoTimeout(5000);

        sender = new BufferedOutputStream(client.getOutputStream());

        receiver = new BufferedInputStream(client.getInputStream());

    }


    /* 关闭与Web服务器的连接 */

    protected void closeServer() throws IOException{

        if(client == null){

            return;

        }

        try{

            client.close();

            sender.close();

            receiver.close();

        }

        catch(IOException i){

            throw i;

        }


        client = null;

        sender = null;

        receiver = null;

    }


    protected String getURLFormat(URL target){

        String spec = "http://" + target.getHost();

        if(target.getPort() != -1){

            spec += ":" + target.getPort();

        }


        return spec += target.getFile();

    }


    /* 向Web服务器传送数据 */

    protected void sendMessage(String data) throws IOException{

        sender.write(data.getBytes(),0,data.length());

        sender.flush();

    }


    /* 接收来自Web服务器的数据 */

    protected void receiveMessage() throws IOException{

        byte data[] = new byte[1024];

        int count = 0;

        int word = -1;

        // 解析第一行

        while( (word = receiver.read()) != -1){

            if(word == '\r' || word == '\n'){

                word = receiver.read();

                if(word == '\n') {

                    word = receiver.read();

                }

                break;

            }

            if(count == data.length) {

                data = addCapacity(data);

            }

            data[count++] = (byte) word;

        }

        String message = new String(data,0,count);

        int mark = message.indexOf(32);

        serverVersion= message.substring(0,mark);

        while(mark < message.length() && message.charAt(mark + 1) == 32) {

            mark++;

        }

        responseCode = Integer.parseInt(message.substring(mark + 1,mark += 4));

        responseMessage = message.substring(mark,message.length()).trim();


        // 应答状态码和处理请读者添加

        switch(responseCode){

            case 400:

                throw new IOException("错误请求");

            case 404:

                throw new FileNotFoundException(getURLFormat(target));

            case 503:

                throw new IOException("服务器不可用");

        }

        if(word == -1){

            throw new ProtocolException("信息接收异常终止");

        }

        int symbol = -1;

        count = 0;

        // 解析元信息

        while(word != '\r' && word != '\n' && word > -1){

            if(word == '\t') {

                word = 32;

            }

            if(count == data.length) {

                data = addCapacity(data);

            }

            data[count++] = (byte) word;

            parseLine:{

                while( (symbol = receiver.read()) > -1){

                    switch(symbol){

                        case '\t':

                            symbol = 32;

                            break;

                        case '\r':

                        case '\n':

                            word = receiver.read();

                            if(symbol == '\r' && word == '\n'){

                                word = receiver.read();

                                if(word == '\r') {

                                    word = receiver.read();

                                }

                            }

                            if(word == '\r' || word == '\n' || word > 32){

                                break parseLine;

                            }

                            symbol = 32;

                            break;

                    }

                    if(count == data.length) {

                        data = addCapacity(data);

                    }

                    data[count++] = (byte) symbol;

                }

                word = -1;

            }

            message = new String(data,0,count);

            mark = message.indexOf(':');

            String key = null;

            if(mark > 0) {

                key = message.substring(0,mark);

            }

            mark++;

            while(mark < message.length() && message.charAt(mark) <= 32) {

                mark++;

            }

            String value = message.substring(mark,message.length());

            header.put(key,value);

            count = 0;

        }

        // 获得正文数据

        while( (word = receiver.read()) != -1){

            if(count == data.length) {

                data = addCapacity(data);

            }

            data[count++] = (byte) word;

        }

        if(count > 0) {

            byteStream = new ByteArrayInputStream(data,0,count);

        }

        data = null;

        closeServer();

    }


    public String getResponseMessage(){

        return responseMessage;

    }


    public int getResponseCode(){

        return responseCode;

    }


    public String getServerVersion(){

        return serverVersion;

    }


    public InputStream getInputStream(){

        return byteStream;

    }


    public synchronized String getHeaderKey(int i){

        if(i >= header.size()){

            return null;

        }

        Enumeration enumss = header.propertyNames();

        String key = null;

        for(int j = 0; j <= i; j++){

            key = (String) enumss.nextElement();

        }

        return key;

    }


    public synchronized String getHeaderValue(int i){

        if(i >= header.size()){

            return null;

        }

        return header.getProperty(getHeaderKey(i));

    }


    public synchronized String getHeaderValue(String key){

        return header.getProperty(key);

    }


    protected String getBaseHeads(){

        String inf = "User-Agent: ZealHttp/1.0\r\nAccept: www/source; text/html; image/gif; */*\r\n";

        return inf;

    }


    private byte[] addCapacity(byte rece[]){

        byte temp[] = new byte[rece.length + 1024];

        System.arraycopy(rece,0,temp,0,rece.length);

        return temp;

    }

}
分享到:
评论

相关推荐

    【转载】java实现的局域网聊天软件

    【Java 实现局域网聊天软件】:这篇文章主要探讨了如何使用Java编程语言来构建一个局域网内的聊天软件,并将其整合到Spring Boot框架中。Java作为一种强大的后端开发语言,其网络通信功能强大,适合构建这样的应用。...

    zookeeper客户端jar包ZooInspector.jar 以及运行命令

    @echo off ...版权声明:本文为CSDN博主「君子志邦」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/u011488009/article/details/104215906

    java编程事项(转载收集整理版)

    7. **网络编程**:Java的Socket编程允许开发网络应用,如客户端和服务端通信。理解TCP和UDP协议,以及ServerSocket和Socket类的使用,是构建网络应用的基础。 8. **反射**:Java的反射机制允许在运行时检查类的信息...

    tomacat8.5 官方

    Apache Tomcat 8支持Java EE 7规范,包括Java Servlet 3.1、JSP 2.3、Java统一表达式语言EL 3.0等。Servlet 3.1最大的改进是实现了非阻塞式的I/O通信。这使得性能得到巨大的改进,数据可以通过ReadListener和...

    Java程序员面试的试题集(1_122)帮助初学者的技术问题(转载)

    3. **ORB协议**:ORB(Object Request Broker)充当应用程序间的中介,负责处理对象请求并进行响应,实现了不同系统间对象的透明交互。 CORBA的引入极大地简化了分布式计算环境中组件之间的交互,尤其在企业级应用...

    HttpClient.jar

    HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。 ———————————————— 版权声明:...

    java J2EE成长之路

    “用 JSP 在客户端生成 JavaScript 代码来实现表单校验.txt”则揭示了如何利用JSP生成JavaScript,实现客户端的表单验证,这是Web应用中常见的用户界面优化技术。 4. **技术比较**:“转载--微软98年关于MTS和EJB的...

    基于Swing的网络聊天室的设计实现

    1、在IDEA中导入提供的Java工程“ChatRoom”,在其中完成后续设计实现。已提供的内容包括:(1)MOYserver包:用于定义服务器端的功能,目前提供了服务器启动及响应客户端连接的功能,也是主要的客户端,每次使用的...

    android http server

    Android HTTP服务器通常基于Java的HTTP服务器实现,如NanoHTTPD或Jetty等。 描述中的“转载 咪当我系欧巴 代码,原始链接在http://download.csdn.net/detail/hellogv/4047134”表明这个项目可能是从某位名为“咪当...

    为RMI实现类Jini的发现机制,转载自:51CTO

    在Java世界中,远程方法调用(Remote Method Invocation, RMI)是一种允许对象在不同的Java虚拟机(JVM)之间进行通信的技术。Jini技术则是RMI的一种扩展,它提供了服务发现和服务注册的功能,使得网络中的分布式...

    Servlet初级学习源代码

    Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。 使用 Servlet,您可以收集来自网页表单的用户输入,...

    JAVA WEB 开发详解:XML+XSLT+SERVLET+JSP 深入剖析与实例应用.part2

    8.1.4 本地协议的纯java驱动程序 256 8.2 安装数据库 256 8.3 jdbc api 260 8.3.1 加载并注册数据库驱动 261 8.3.2 建立到数据库的连接 263 8.3.3 访问数据库 264 8.3.4 事务处理 289 8.3.5 可滚动和可更新的...

    视频监控源码(转载)

    源码可能采用了RTSP(Real-Time Streaming Protocol)或HTTP Live Streaming (HLS)等协议来实现实时传输。RTSP常用于专业级监控,而HLS更适合互联网环境。 3. 视频编码与解码:为了减小带宽需求,视频通常需要进行...

    JAVA WEB 开发详解:XML+XSLT+SERVLET+JSP 深入剖析与实例应用.part3

    8.1.4 本地协议的纯java驱动程序 256 8.2 安装数据库 256 8.3 jdbc api 260 8.3.1 加载并注册数据库驱动 261 8.3.2 建立到数据库的连接 263 8.3.3 访问数据库 264 8.3.4 事务处理 289 8.3.5 可滚动和可更新的...

    JAVA WEB 开发详解:XML+XSLT+SERVLET+JSP 深入剖析与实例应用.part4

    8.1.4 本地协议的纯java驱动程序 256 8.2 安装数据库 256 8.3 jdbc api 260 8.3.1 加载并注册数据库驱动 261 8.3.2 建立到数据库的连接 263 8.3.3 访问数据库 264 8.3.4 事务处理 289 8.3.5 可滚动和可更新的...

    WebService+Android

    3. **Retrofit**: 是一个现代的、类型安全的HTTP客户端,适用于Android和Java。它可以与Gson、Jackson等库无缝集成,自动将JSON数据转换为Java对象,简化了Web服务的调用过程。 4. **OkHttp**: 作为底层网络库,...

    apache-cxf-3.3.4.rar

    版权声明:本文为CSDN博主「写程序的小白」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_36970062/article/details/79731681

    WCF 分布式开发转载

    学习WCF时,可以创建简单的客户端和服务端项目进行实战练习,比如模拟一个文件上传服务。通过实际操作,理解服务的生命周期、错误处理、调试工具的使用等。 总之,WCF是一个强大的分布式系统开发工具,它将面向服务...

    Java23种设计模式

    Java23种设计模式的知识点...文档遵循了Apache2.0协议,允许和鼓励全文转载及推广,但保留了作者的署名权。作者还提供了自己的邮箱和所参与的疯狂Java联盟的网址,以便读者能够更好地与作者联系和讨论相关技术问题。

Global site tag (gtag.js) - Google Analytics