`
soardragon
  • 浏览: 316463 次
  • 性别: Icon_minigender_1
  • 来自: 郑州
社区版块
存档分类
最新评论

用Socket类实现HTTP协议客户端应用

阅读更多
Http客户端程序已集成在Java语言中,可以通过URLConnection类调用。遗憾的
是,由于SUN没有公布Http客户程序的源码,它实现的细节仍是一个谜。本文根据HTTP
协议规范,用Java.net.Socket类实现一个HTTP协议客户端程序。

1.Socket类:
了解TCP/IP协议集通信的读者知道,协议间的通信是通过Socket完成的。在
Java.net包中,Socket类就是对Socket的具体实现。它通过连接到主机后,返回一个
I/O流,实现协议间的信息交换。

2.HTTP协议
HTTP协议同其它TCP/IP协议集中的协议一样,是遵循客户/服务器模型工作的。客
户端发往服务端的信息格式如下:
------------------------------
请求方法URLHTTP协议的版本号
提交的元信息
**空行**
实体
------------------------------
请求方法是对这次连接工作的说明,目前HTTP协议已经发展到1.1版,它包括GET、
HEAD、POST、DELETE、OPTIONS、TRACE、PUT七种。元信息是关于当前请求的信息。通
过分析元信息,可以检查实体数据是否完整,接收过程是否出错,类型是否匹配等。元
信息的引入使HTTP协议通信更加稳妥可靠。实体是请求的具体内容。
将上述报文发往Web服务器,如果成功,应答格式如下:
--------------------------------
HTTP协议的版本号应答状态码应答状态码说明
接收的元信息
**空行**
实体
--------------------------------
以上报文发向客户端,并且接收成功,彼此间关闭连接,完成一次握手。
下面用最常用的GET方法,来说明具体的报文应用
----------------------------------
GEThttp://www.youhost.comHTTP/1.0
accept:www/source;text/html;image/gif;image/jpeg;*/*
User_Agent:myAgent
**空行**
-----------------------------------
这个报文是向www.youhost.com主机请求一个缺省HTML文档。客户端HTTP协议版本
号是1.0版,元信息包括可接收的文件格式,用户代理,每一段之间用回车换行符分
隔,最后以一个空行结束。发向服务器后,如果执行过程正常,服务器返回以下代码:
------------------------------------
HTTP/1.1200OK
Date:Tue,14Sep199902:19:57GMT
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)。

3.HTTP客户端程序:

importjava.net.*;
importjava.io.*;
importjava.util.Properties;
importjava.util.Enumeration;
publicclassHttp{
protectedSocketclient;
protectedBufferedOutputStreamsender;
protectedBufferedInputStreamreceiver;
protectedByteArrayInputStreambyteStream;
protectedURLtarget;
privateintresponseCode=-1;
privateStringresponseMessage="";
privateStringserverVersion="";
privatePropertiesheader=newProperties();
publicHttp(){}
publicHttp(Stringurl){
GET(url);
}
/*GET方法根据URL,会请求文件、数据库查询结果、程序运行结果等多种内容*/
publicvoidGET(Stringurl){
try{
checkHTTP(url);
openServer(target.getHost(),target.getPort());
Stringcmd="GET"+getURLFormat(target)+"HTTP/1.0\r\n"
+getBaseHeads()+"\r\n";
sendMessage(cmd);
receiveMessage();
}catch(ProtocolExceptionp){
p.printStackTrace();
return;
}catch(UnknownHostExceptione){
e.printStackTrace();
return;
}catch(IOExceptioni)

i.printStackTrace();
return;
}
}

/*
*HEAD方法只请求URL的元信息,不包括URL本身。若怀疑本机和服务器上的
*文件相同,用这个方法检查最快捷有效。
*/
publicvoidHEAD(Stringurl){
try{
checkHTTP(url);
openServer(target.getHost(),target.getPort());
Stringcmd="HEAD"+getURLFormat(target)+"HTTP/1.0\r\n"
+getBaseHeads()+"\r\n";
sendMessage(cmd);
receiveMessage();
}catch(ProtocolExceptionp){
p.printStackTrace();
return;
}catch(UnknownHostExceptione){
e.printStackTrace();
return;
}catch(IOExceptioni)

i.printStackTrace();
return;
}
}
/*
*POST方法是向服务器传送数据,以便服务器做出相应的处理。例如网页上常用的
*提交表格。
*/
publicvoidPOST(Stringurl,Stringcontent){
try{
checkHTTP(url);
openServer(target.getHost(),target.getPort());
Stringcmd="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(ProtocolExceptionp){
p.printStackTrace();
return;
}catch(UnknownHostExceptione){
e.printStackTrace();
return;
}catch(IOExceptioni)

i.printStackTrace();
return;
}

}
protectedvoidcheckHTTP(Stringurl)throwsProtocolException{
try{
URLtarget=newURL(url);
if(target==null||!target.getProtocol().toUpperCase().equals("HTTP"))
thrownewProtocolException("这不是HTTP协议");
this.target=target;
}catch(MalformedURLExceptionm){
thrownewProtocolException("协议格式错误");
}
}
/*
*与Web服务器连接。若找不到Web服务器,InetAddress会引发UnknownHostException
*异常。若Socket连接失败,会引发IOException异常。
*/
protectedvoidopenServer(Stringhost,intport)throws
UnknownHostException,IOException{
header.clear();
responseMessage="";responseCode=-1;
try{
if(client!=null)closeServer();
if(byteStream!=null){
byteStream.close();byteStream=null;
}
InetAddressaddress=InetAddress.getByName(host);
client=newSocket(address,port==-1?80:port);
sender=newBufferedOutputStream(client.getOutputStream());
receiver=newBufferedInputStream(client.getInputStream());
}catch(UnknownHostExceptionu){
throwu;
}catch(IOExceptioni){
throwi;
}
}
/*关闭与Web服务器的连接*/
protectedvoidcloseServer()throwsIOException{
if(client==null)return;
try{
client.close();sender.close();receiver.close();
}catch(IOExceptioni){
throwi;
}
client=null;sender=null;receiver=null;
}
protectedStringgetURLFormat(URLtarget){
Stringspec="http://"+target.getHost();
if(target.getPort()!=-1)
spec+=":"+target.getPort();
returnspec+=target.getFile();
}

/*向Web服务器传送数据*/
protectedvoidsendMessage(Stringdata)throwsIOException{
sender.write(data.getBytes(),0,data.length());
sender.flush();
}
/*接收来自Web服务器的数据*/
protectedvoidreceiveMessage()throwsIOException{
bytedata[]=newbyte[1024];
intcount=0;
intword=-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;
}
Stringmessage=newString(data,0,count);
intmark=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){
case400:
thrownewIOException("错误请求");
case404:
thrownewFileNotFoundException(getURLFormat(target));
case503:
thrownewIOException("服务器不可用");
}
if(word==-1)thrownewProtocolException("信息接收异常终止");
intsymbol=-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)breakparseLine;
symbol=32;break;
}
if(count==data.length)data=addCapacity(data);
data[count++]=(byte)symbol;
}
word=-1;
}
message=newString(data,0,count);
mark=message.indexOf(':');
Stringkey=null;
if(mark>0)key=message.substring(0,mark);
mark++;
while(mark<message.length()&&message.charAt(mark)<=32)mark++;
Stringvalue=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=newByteArrayInputStream(data,0,count);
data=null;
closeServer();
}
publicStringgetResponseMessage(){
returnresponseMessage;
}
publicintgetResponseCode(){
returnresponseCode;
}
publicStringgetServerVersion(){
returnserverVersion;
}
publicInputStreamgetInputStream(){
returnbyteStream;
}
publicsynchronizedStringgetHeaderKey(inti){
if(i>=header.size())returnnull;
Enumerationenum=header.propertyNames();
Stringkey=null;
for(intj=0;j<=i;j++)
key=(String)enum.nextElement();
returnkey;
}
publicsynchronizedStringgetHeaderValue(inti){
if(i>=header.size())returnnull;
returnheader.getProperty(getHeaderKey(i));
}
publicsynchronizedStringgetHeaderValue(Stringkey){
returnheader.getProperty(key);
}
protectedStringgetBaseHeads(){
Stringinf="User-Agent:myselfHttp/1.0\r\n"+
"Accept:www/source;text/html;image/gif;*/*\r\n";
returninf;
}
privatebyte[]addCapacity(byterece[]){
bytetemp[]=newbyte[rece.length+1024];
System.arraycopy(rece,0,temp,0,rece.length);
returntemp;
}
}

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

相关推荐

    用Socket套接字实现DAYTIME协议的服务器和客户端程序.doc

    DAYTIME 协议服务器和客户端程序使用 Socket 套接字实现 知识点 1:DAYTIME 协议的定义和应用 * DAYTIME 协议是一种简单的网络协议,用于获取服务器的当前时间 *DAYTIME 协议通常使用 TCP 或 UDP 协议进行数据传输...

    HPSocket--UDP传输客户端应用实例

    本文将深入解析标题为“HPSocket--UDP传输客户端应用实例”的技术要点,以及如何利用HPsocket框架实现UDP协议的客户端功能。 首先,HPSocket是一款强大的网络通信组件,它提供了丰富的接口,支持多种协议(如TCP、...

    SuperSocket 入门,实现客户端和服务端消息互发

    SuperSocket 提供了一个高效、灵活的平台,使得开发者可以快速构建Socket应用程序,尤其适合需要实现客户端与服务器之间实时通信的场景。通过以上步骤,你将能够成功地搭建一个基础的SuperSocket客户端和服务端,...

    C#使用SuperSocket实现自定义协议实现CS架构服务器和客户端程序设计).zip

    在本项目中,"C#使用SuperSocket实现自定义协议实现CS架构服务器和客户端程序设计"),开发者利用C#编程语言以及SuperSocket开源库构建了一套C/S(客户端/服务器)架构的应用。SuperSocket是一个轻量级、高度可扩展的...

    使用java控制HTTP协议客户端应用.rar_HTTP java_HTTP 协议 客户端_HTTP协议_java http_j

    Http客户端程序已集成在Java语言中,可以通过URLConnection类调用。遗憾的是,由于SUN没有公布Http客户程序的源码,它实现的细节仍是一个谜...本文根据HTTP协议规范,用Java.net.Socket类实现一个HTTP协议客户端程序。

    Java基于socket实现的客户端和服务端通信功能完整实例

    Java中提供了Socket类来实现网络通信,Socket类位于java.net包中,提供了多种方法来实现Socket的操作,如connect、send、receive等。Java中的Socket可以分为两种:ServerSocket和Socket。ServerSocket用于建立服务器...

    socket实现ftp客户端

    根据给定的文件标题、描述、标签以及部分内容,我们可以总结出以下关于使用Socket...通过以上分析,我们可以看出,使用Socket实现FTP客户端涉及到网络编程、C#语言特性以及对FTP协议的理解,是一项综合性较强的技能。

    Socket实现服务端与客户端通讯

    在Socket编程中,我们通常会使用BufferedReader和PrintWriter类来处理输入输出流,因为它们提供了方便的读写文本数据的方法。例如,服务端可以创建一个BufferedReader来读取客户端的输入,而客户端则可以创建一个...

    C语言利用socket套接字实现客户端和服务器端TCP通信实例

    本篇将详细探讨如何利用C语言的socket套接字实现客户端和服务器端的TCP通信。 TCP(Transmission Control Protocol)是一种面向连接的、可靠的传输协议,它通过三次握手建立连接,并在数据传输过程中进行确认和重传...

    C++ 纯SOCKET实现FTP客户端类

    综上所述,这个"C++纯SOCKET实现FTP客户端类"项目涵盖了网络编程的基础,FTP协议的应用,以及C++面向对象编程的实践。对于学习网络编程和FTP客户端实现的初学者来说,这是一个很好的起点。通过分析和理解项目中的...

    C#使用Socket实现服务器与多个客户端通信(简单的聊天系统)

    在本文中,我们将深入探讨如何使用C#编程语言通过Socket实现一个简单的聊天系统,使得服务器可以与多个客户端进行通信。Socket在计算机网络编程中扮演着重要角色,它提供了进程间通信(IPC)的能力,允许不同计算机...

    Socket服务端客户端以tcp/ip协议发送接收报文

    通过这种方式,Java Socket编程实现了基于TCP/IP协议的服务端和客户端通信。每个报文的发送和接收都依赖于`InputStream`和`OutputStream`对象,它们分别用于读取和写入网络数据。在实际应用中,可能需要对报文进行更...

    C#的Socket实现UDP协议通信

    标题和描述中的知识点聚焦于如何使用C#的Socket类实现UDP协议通信,这涉及到了UDP协议的基本特性以及在C#中的具体实现方法。以下是对这一主题的深入解析: ### UDP协议简介 用户数据报协议(UDP)是互联网协议族中...

    socket5协议简单客户端

    本项目中,我们关注的是一个使用QT库实现的简单Socket5协议客户端。QTCPsocket是Qt库中的一个关键组件,专门用于处理TCP套接字连接,而QThread则是用来实现多线程编程,提升程序性能和响应性。 首先,让我们深入...

    http协议客户端编程

    ### HTTP协议客户端编程 #### 一、概述 HTTP(HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议,主要用于从WWW服务器传输超文本到本地浏览器的传输协议。本文主要介绍如何利用Java语言中的`...

    基于TCP的Socket编程服务器和客户端代码

    本主题聚焦于使用Java进行基于TCP的Socket编程,通过`File_client.java`和`File_server.java`两个文件来实现服务器和客户端之间的数据交换。 首先,TCP Socket编程的基础是Java的`java.net.Socket`和`java.net....

    C# Socket 客户端服务端封装带使用实例

    1. 创建Socket实例:使用Socket类的构造函数初始化Socket对象,指定协议类型(如SocketType.Stream代表TCP)。 2. 连接服务器:调用Connect方法,传入服务器的IP地址和端口号。 3. 数据收发:使用Socket的Receive和...

    C#SuperSocket---客户端源程序

    文件列表中的"SocketServer(C#SuperSocket服务器的简易实现)---客户端源程序",暗示了这个压缩包不仅包含了一个简单的SuperSocket服务器实现,还包含了与之配合使用的客户端源代码。客户端源程序通常会包含一个或...

    使用Socket通信实现FTP客户端程序.docx

    FTP 客户端程序是基于 Socket 通信实现的文件传输协议,在网络应用软件中具有广泛的应用。FTP 的目标是提高文件的共享性和可靠高效地传送数据。FTP 协议与操作系统无关,任何操作系统上的程序只要符合 FTP 协议,就...

Global site tag (gtag.js) - Google Analytics