⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 用socket类实现http协议客户端应用.htm

📁 写给JSP初级程序员的书
💻 HTM
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0057)http://eps.www85.cn4e.com/java/article/devshow.asp?id=161 -->
<HTML><HEAD><title>csdn_ 用Socket类实现HTTP协议客户端应用</TITLE>
<META content="text/html; charset=gb2312" http-equiv=Content-Type>
<STYLE type=text/css>TD {
	FONT-FAMILY: "Verdana", "Arial", "宋体"; FONT-SIZE: 9pt
}
A {
	COLOR: #660000; TEXT-DECORATION: underline
}
A:hover {
	COLOR: #660000; TEXT-DECORATION: none
}
.line {
	LINE-HEIGHT: 14pt
}
</STYLE>

<META content="MSHTML 5.00.2920.0" name=GENERATOR></HEAD>
<BODY bgColor=#ffffff text=#000000>
<table>
  <TBODY>
  <TR>
    <TD height=21>
      <DIV align=center><B><FONT  size=3> 用Socket类实现HTTP协议客户端应用 
      <BR><FONT size=2> </FONT></FONT></FONT>
      <HR align=center color=#cccccc noShade SIZE=1>
      </DIV></TD></TR>
  <TR>
    <TD class=line><FONT 
      color=#333300>用Socket类实现HTTP协议客户端应用<BR><BR>&nbsp;<BR>梁颖健&nbsp;<BR>liangyingjian@21cn.com&nbsp;<BR><BR>Http客户端程序已集成在Java语言中,可以通过URLConnection类调用。遗憾的<BR>是,由于SUN没有公布Http客户程序的源码,它实现的细节仍是一个谜。本文根据HTTP<BR>协议规范,用Java.net.Socket类实现一个HTTP协议客户端程序。<BR><BR>1.Socket类:<BR>了解TCP/IP协议集通信的读者知道,协议间的通信是通过Socket完成的。在<BR>Java.net包中,Socket类就是对Socket的具体实现。它通过连接到主机后,返回一个<BR>I/O流,实现协议间的信息交换。<BR><BR>2&nbsp;.&nbsp;HTTP协议<BR>HTTP协议同其它TCP/IP协议集中的协议一样,是遵循客户/服务器模型工作的。客<BR>户端发往服务端的信息格式如下:<BR>------------------------------<BR>请求方法&nbsp;URL&nbsp;HTTP协议的版本号<BR>提交的元信息<BR>**空行**<BR>实体<BR>------------------------------<BR>请求方法是对这次连接工作的说明,目前HTTP协议已经发展到1.1版,它包括GET、<BR>HEAD、POST、DELETE、OPTIONS、TRACE、PUT七种。元信息是关于当前请求的信息。通<BR>过分析元信息,可以检查实体数据是否完整,接收过程是否出错,类型是否匹配等。元<BR>信息的引入使HTTP协议通信更加稳妥可靠。实体是请求的具体内容。<BR>将上述报文发往Web服务器,如果成功,应答格式如下:<BR>--------------------------------<BR>HTTP协议的版本号&nbsp;应答状态码&nbsp;应答状态码说明<BR>接收的元信息<BR>**空行**<BR>实体<BR>--------------------------------<BR>以上报文发向客户端,并且接收成功,彼此间关闭连接,完成一次握手。<BR>下面用最常用的GET方法,来说明具体的报文应用<BR>----------------------------------<BR>GET&nbsp;http://www.youhost.com&nbsp;HTTP/1.0<BR>accept:&nbsp;www/source;&nbsp;text/html;&nbsp;image/gif;&nbsp;image/jpeg;&nbsp;*/*<BR>User_Agent:&nbsp;myAgent<BR>**空行**<BR>-----------------------------------<BR>这个报文是向www.youhost.com主机请求一个缺省HTML文档。客户端HTTP协议版本<BR>号是1.0版,元信息包括可接收的文件格式,用户代理,每一段之间用回车换行符分<BR>隔,最后以一个空行结束。发向服务器后,如果执行过程正常,服务器返回以下代码:<BR>------------------------------------<BR>HTTP/1.1&nbsp;200&nbsp;OK<BR>Date:&nbsp;Tue,&nbsp;14&nbsp;Sep&nbsp;1999&nbsp;02:19:57&nbsp;GMT<BR>Server:&nbsp;Apache/1.2.6<BR>Connection:&nbsp;close<BR>Content-Type:&nbsp;text/html<BR>**空行**<BR>&lt;html&gt;&lt;head&gt;...&lt;/head&gt;&lt;body&gt;...&lt;/body&gt;&lt;/html&gt;<BR>------------------------------------<BR>HTTP/1.1表示这个HTTP服务器是1.1版,200是服务器对客户请求的应答状态码,OK<BR>是对应答状态码的解释,之后是这个文档的元信息和文档正文。(相关应答状态码和元<BR>信息的解释请参阅Inetrnet标准草案:RFC2616)。<BR><BR>3.&nbsp;HTTP客户端程序:<BR><BR>import&nbsp;java.net.*;<BR>import&nbsp;java.io.*;<BR>import&nbsp;java.util.Properties;<BR>import&nbsp;java.util.Enumeration;<BR>public&nbsp;class&nbsp;Http&nbsp;{<BR>protected&nbsp;Socket&nbsp;client;<BR>protected&nbsp;BufferedOutputStream&nbsp;sender;<BR>protected&nbsp;BufferedInputStream&nbsp;receiver;<BR>protected&nbsp;ByteArrayInputStream&nbsp;byteStream;<BR>protected&nbsp;URL&nbsp;target;<BR>private&nbsp;int&nbsp;responseCode=-1;<BR>private&nbsp;String&nbsp;responseMessage="";<BR>private&nbsp;String&nbsp;serverVersion="";<BR>private&nbsp;Properties&nbsp;header&nbsp;=&nbsp;new&nbsp;Properties();<BR>public&nbsp;Http()&nbsp;{&nbsp;}<BR>public&nbsp;Http(String&nbsp;url)&nbsp;{<BR>GET(url)&nbsp;;<BR>}<BR>/*&nbsp;GET方法根据URL,会请求文件、数据库查询结果、程序运行结果等多种内容&nbsp;*/<BR>public&nbsp;void&nbsp;GET(String&nbsp;url)&nbsp;{<BR>try&nbsp;{<BR>checkHTTP(url);<BR>openServer(target.getHost(),target.getPort()&nbsp;);<BR>String&nbsp;cmd&nbsp;=&nbsp;"GET&nbsp;"+&nbsp;getURLFormat(target)&nbsp;+"&nbsp;HTTP/1.0\r\n"<BR>+&nbsp;getBaseHeads()+"\r\n";<BR>sendMessage(cmd);<BR>receiveMessage();<BR>}catch(ProtocolException&nbsp;p)&nbsp;{<BR>p.printStackTrace();<BR>return;<BR>}catch(UnknownHostException&nbsp;e)&nbsp;{<BR>e.printStackTrace();<BR>return;<BR>}catch(IOException&nbsp;i)<BR><BR>i.printStackTrace();<BR>return;<BR>}<BR>}<BR><BR>/*<BR>*&nbsp;HEAD方法只请求URL的元信息,不包括URL本身。若怀疑本机和服务器上的<BR>*&nbsp;文件相同,用这个方法检查最快捷有效。<BR>*/<BR>public&nbsp;void&nbsp;HEAD(String&nbsp;url)&nbsp;{<BR>try&nbsp;{<BR>checkHTTP(url);<BR>openServer(target.getHost(),target.getPort()&nbsp;);<BR>String&nbsp;cmd&nbsp;=&nbsp;"HEAD&nbsp;"+getURLFormat(target)+"&nbsp;HTTP/1.0\r\n"<BR>+getBaseHeads()+"\r\n";<BR>sendMessage(cmd);<BR>receiveMessage();<BR>}catch(ProtocolException&nbsp;p)&nbsp;{<BR>p.printStackTrace();<BR>return;<BR>}catch(UnknownHostException&nbsp;e)&nbsp;{<BR>e.printStackTrace();<BR>return;<BR>}catch(IOException&nbsp;i)<BR><BR>i.printStackTrace();<BR>return;<BR>}<BR>}<BR>/*<BR>*&nbsp;POST方法是向服务器传送数据,以便服务器做出相应的处理。例如网页上常用的<BR>*&nbsp;提交表格。<BR>*/<BR>public&nbsp;void&nbsp;POST(String&nbsp;url,String&nbsp;content)&nbsp;{<BR>try&nbsp;{<BR>checkHTTP(url);<BR>openServer(target.getHost(),target.getPort()&nbsp;);<BR>String&nbsp;cmd&nbsp;=&nbsp;"POST&nbsp;"+&nbsp;getURLFormat(target)&nbsp;+"<BR>HTTP/1.0\r\n"+getBaseHeads();<BR>cmd&nbsp;+=&nbsp;"Content-type:&nbsp;application/x-www-form-urlencoded\r\n";<BR>cmd&nbsp;+=&nbsp;"Content-length:&nbsp;"&nbsp;+&nbsp;content.length()&nbsp;+&nbsp;"\r\n\r\n";<BR>cmd&nbsp;+=&nbsp;content+"\r\n";<BR>sendMessage(cmd);<BR>receiveMessage();<BR>}catch(ProtocolException&nbsp;p)&nbsp;{<BR>p.printStackTrace();<BR>return;<BR>}catch(UnknownHostException&nbsp;e)&nbsp;{<BR>e.printStackTrace();<BR>return;<BR>}catch(IOException&nbsp;i)<BR><BR>i.printStackTrace();<BR>return;<BR>}<BR><BR>}<BR>protected&nbsp;void&nbsp;checkHTTP(String&nbsp;url)&nbsp;throws&nbsp;ProtocolException&nbsp;{<BR>try&nbsp;{<BR>URL&nbsp;target&nbsp;=&nbsp;new&nbsp;URL(url);<BR>if(target==null&nbsp;||&nbsp;!target.getProtocol().toUpperCase().equals("HTTP")&nbsp;)<BR>throw&nbsp;new&nbsp;ProtocolException("这不是HTTP协议");<BR>this.target&nbsp;=&nbsp;target;<BR>}catch(MalformedURLException&nbsp;m)&nbsp;{<BR>throw&nbsp;new&nbsp;ProtocolException("协议格式错误");<BR>}<BR>}<BR>/*<BR>*&nbsp;与Web服务器连接。若找不到Web服务器,InetAddress会引发UnknownHostException<BR>*&nbsp;异常。若Socket连接失败,会引发IOException异常。<BR>*/<BR>protected&nbsp;void&nbsp;openServer(String&nbsp;host,int&nbsp;port)&nbsp;throws<BR>UnknownHostException,IOException&nbsp;{<BR>header.clear();<BR>responseMessage="";&nbsp;responseCode=-1;<BR>try&nbsp;{<BR>if(client!=null)&nbsp;closeServer();<BR>if(byteStream&nbsp;!=&nbsp;null)&nbsp;{<BR>byteStream.close();&nbsp;byteStream=null;<BR>}<BR>InetAddress&nbsp;address&nbsp;=&nbsp;InetAddress.getByName(host);<BR>client&nbsp;=&nbsp;new&nbsp;Socket(address,port==-1?80:port);<BR>sender&nbsp;=&nbsp;new&nbsp;BufferedOutputStream(client.getOutputStream());<BR>receiver&nbsp;=&nbsp;new&nbsp;BufferedInputStream(client.getInputStream());<BR>}catch(UnknownHostException&nbsp;u)&nbsp;{<BR>throw&nbsp;u;<BR>}catch(IOException&nbsp;i)&nbsp;{<BR>throw&nbsp;i;<BR>}<BR>}<BR>/*&nbsp;关闭与Web服务器的连接&nbsp;*/<BR>protected&nbsp;void&nbsp;closeServer()&nbsp;throws&nbsp;IOException&nbsp;{<BR>if(client==null)&nbsp;return;<BR>try&nbsp;{<BR>client.close();&nbsp;sender.close();&nbsp;receiver.close();<BR>}catch(IOException&nbsp;i)&nbsp;{<BR>throw&nbsp;i;<BR>}<BR>client=null;&nbsp;sender=null;&nbsp;receiver=null;<BR>}<BR>protected&nbsp;String&nbsp;getURLFormat(URL&nbsp;target)&nbsp;{<BR>String&nbsp;spec&nbsp;=&nbsp;"http://"+target.getHost();<BR>if(target.getPort()!=-1)<BR>spec+=":"+target.getPort();<BR>return&nbsp;spec+=target.getFile();<BR>}<BR><BR>/*&nbsp;向Web服务器传送数据&nbsp;*/<BR>protected&nbsp;void&nbsp;sendMessage(String&nbsp;data)&nbsp;throws&nbsp;IOException{<BR>sender.write(data.getBytes(),0,data.length());<BR>sender.flush();<BR>}<BR>/*&nbsp;接收来自Web服务器的数据&nbsp;*/<BR>protected&nbsp;void&nbsp;receiveMessage()&nbsp;throws&nbsp;IOException{<BR>byte&nbsp;data[]&nbsp;=&nbsp;new&nbsp;byte[1024];<BR>int&nbsp;count=0;<BR>int&nbsp;word=-1;<BR>//&nbsp;解析第一行<BR>while(&nbsp;(word=receiver.read())!=-1&nbsp;)&nbsp;{<BR>if(word=='\r'||word=='\n')&nbsp;{<BR>word=receiver.read();<BR>if(word=='\n')&nbsp;word=receiver.read();<BR>break;<BR>}<BR>if(count&nbsp;==&nbsp;data.length)&nbsp;data&nbsp;=&nbsp;addCapacity(data);<BR>data[count++]=(byte)word;<BR>}<BR>String&nbsp;message&nbsp;=&nbsp;new&nbsp;String(data,0,count);<BR>int&nbsp;mark&nbsp;=&nbsp;message.indexOf(32);<BR>serverVersion&nbsp;=&nbsp;message.substring(0,mark);<BR>while(&nbsp;mark&lt;message.length()&nbsp;&amp;&amp;&nbsp;message.charAt(mark+1)==32&nbsp;)&nbsp;mark++;<BR>responseCode&nbsp;=&nbsp;Integer.parseInt(message.substring(mark+1,mark+=4));<BR>responseMessage&nbsp;=&nbsp;message.substring(mark,message.length()).trim();<BR><BR>//&nbsp;应答状态码和处理请读者添加<BR>switch(responseCode)&nbsp;{<BR>case&nbsp;400:<BR>throw&nbsp;new&nbsp;IOException("错误请求");<BR>case&nbsp;404:<BR>throw&nbsp;new&nbsp;FileNotFoundException(&nbsp;getURLFormat(target)&nbsp;);<BR>case&nbsp;503:<BR>throw&nbsp;new&nbsp;IOException("服务器不可用"&nbsp;);<BR>}<BR>if(word==-1)&nbsp;throw&nbsp;new&nbsp;ProtocolException("信息接收异常终止");<BR>int&nbsp;symbol=-1;<BR>count=0;<BR>//&nbsp;解析元信息<BR>while(&nbsp;word!='\r'&nbsp;&amp;&amp;&nbsp;word!='\n'&nbsp;&amp;&amp;&nbsp;word&gt;-1)&nbsp;{<BR>if(word=='\t')&nbsp;word=32;<BR>if(count==data.length)&nbsp;data&nbsp;=&nbsp;addCapacity(data);<BR>data[count++]&nbsp;=&nbsp;(byte)word;<BR>parseLine:&nbsp;{<BR>while(&nbsp;(symbol=receiver.read())&nbsp;&gt;-1&nbsp;)&nbsp;{<BR>switch(symbol)&nbsp;{<BR>case&nbsp;'\t':<BR>symbol=32;&nbsp;break;<BR>case&nbsp;'\r':<BR>case&nbsp;'\n':<BR>word&nbsp;=&nbsp;receiver.read();<BR>if(&nbsp;symbol=='\r'&nbsp;&amp;&amp;&nbsp;word=='\n')&nbsp;{<BR>word=receiver.read();<BR>if(word=='\r')&nbsp;word=receiver.read();<BR>}<BR>if(&nbsp;word=='\r'&nbsp;||&nbsp;word=='\n'&nbsp;||&nbsp;word&gt;32)&nbsp;break&nbsp;parseLine;<BR>symbol=32;&nbsp;break;<BR>}<BR>if(count==data.length)&nbsp;data&nbsp;=&nbsp;addCapacity(data);<BR>data[count++]&nbsp;=&nbsp;(byte)symbol;<BR>}<BR>word=-1;<BR>}<BR>message&nbsp;=&nbsp;new&nbsp;String(data,0,count);<BR>mark&nbsp;=&nbsp;message.indexOf(':');<BR>String&nbsp;key&nbsp;=&nbsp;null;<BR>if(mark&gt;0)&nbsp;key&nbsp;=&nbsp;message.substring(0,mark);<BR>mark++;<BR>while(&nbsp;mark&lt;message.length()&nbsp;&amp;&amp;&nbsp;message.charAt(mark)&lt;=32&nbsp;)&nbsp;mark++;<BR>String&nbsp;value&nbsp;=&nbsp;message.substring(mark,message.length()&nbsp;);<BR>header.put(key,value);<BR>count=0;<BR>}<BR>//&nbsp;获得正文数据<BR>while(&nbsp;(word=receiver.read())!=-1)&nbsp;{<BR>if(count&nbsp;==&nbsp;data.length)&nbsp;data&nbsp;=&nbsp;addCapacity(data);<BR>data[count++]&nbsp;=&nbsp;(byte)word;<BR>}<BR>if(count&gt;0)&nbsp;byteStream&nbsp;=&nbsp;new&nbsp;ByteArrayInputStream(data,0,count);<BR>data=null;<BR>closeServer();<BR>}<BR>public&nbsp;String&nbsp;getResponseMessage()&nbsp;{<BR>return&nbsp;responseMessage;<BR>}<BR>public&nbsp;int&nbsp;getResponseCode()&nbsp;{<BR>return&nbsp;responseCode;<BR>}<BR>public&nbsp;String&nbsp;getServerVersion()&nbsp;{<BR>return&nbsp;serverVersion;<BR>}<BR>public&nbsp;InputStream&nbsp;getInputStream()&nbsp;{<BR>return&nbsp;byteStream;<BR>}<BR>public&nbsp;synchronized&nbsp;String&nbsp;getHeaderKey(int&nbsp;i)&nbsp;{<BR>if(i&gt;=header.size())&nbsp;return&nbsp;null;<BR>Enumeration&nbsp;enum&nbsp;=&nbsp;header.propertyNames();<BR>String&nbsp;key&nbsp;=&nbsp;null;<BR>for(int&nbsp;j=0;&nbsp;j&lt;=i;&nbsp;j++)<BR>key&nbsp;=&nbsp;(String)enum.nextElement();<BR>return&nbsp;key;<BR>}<BR>public&nbsp;synchronized&nbsp;String&nbsp;getHeaderValue(int&nbsp;i)&nbsp;{<BR>if(i&gt;=header.size())&nbsp;return&nbsp;null;<BR>return&nbsp;header.getProperty(getHeaderKey(i));<BR>}<BR>public&nbsp;synchronized&nbsp;String&nbsp;getHeaderValue(String&nbsp;key)&nbsp;{<BR>return&nbsp;header.getProperty(key);<BR>}<BR>protected&nbsp;String&nbsp;getBaseHeads()&nbsp;{<BR>String&nbsp;inf&nbsp;=&nbsp;"User-Agent:&nbsp;myselfHttp/1.0\r\n"+<BR>"Accept:&nbsp;www/source;&nbsp;text/html;&nbsp;image/gif;&nbsp;*/*\r\n";<BR>return&nbsp;inf;<BR>}<BR>private&nbsp;byte[]&nbsp;addCapacity(byte&nbsp;rece[]){<BR>byte&nbsp;temp[]&nbsp;=&nbsp;new&nbsp;byte[rece.length+1024];<BR>System.arraycopy(rece,0,temp,0,rece.length);<BR>return&nbsp;temp;<BR>}<BR>}<BR><BR>注:&nbsp;程序中只实现GET、HEAD、POST三种方法。其他几种因不常使用,暂且忽略。<BR>&nbsp;<BR></FONT></TD></TR>
  <TR>
    <TD height=5>
      <HR align=center color=#cccccc noShade SIZE=1>
    </TD></TR></TBODY></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -